mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-22 21:36:11 +02:00
improved payload handling (retransmit all fragments on CRC error)
improved `isAvailable`, checkes all record structs, inverter becomes available more early because version is check first fix tickers were not set if NTP is not available disabled annoying `FlashStringHelper` it gives randomly Expeptions during development, feels more stable since then moved erase button to the bottom in settings, not nice but more functional split `tx_count` to `tx_cnt` and `retransmits` in `system.html` fix mqtt retransmit IP address #602 added debug infos for `scheduler` (web -> `/debug` as trigger prints list of tickers to serial console)
This commit is contained in:
parent
3d3e3dc8c6
commit
3adcb68d98
19 changed files with 191 additions and 115 deletions
|
@ -2,6 +2,16 @@
|
||||||
|
|
||||||
(starting from release version `0.5.66`)
|
(starting from release version `0.5.66`)
|
||||||
|
|
||||||
|
## 0.5.74
|
||||||
|
* improved payload handling (retransmit all fragments on CRC error)
|
||||||
|
* improved `isAvailable`, checkes all record structs, inverter becomes available more early because version is check first
|
||||||
|
* fix tickers were not set if NTP is not available
|
||||||
|
* disabled annoying `FlashStringHelper` it gives randomly Expeptions during development, feels more stable since then
|
||||||
|
* moved erase button to the bottom in settings, not nice but more functional
|
||||||
|
* split `tx_count` to `tx_cnt` and `retransmits` in `system.html`
|
||||||
|
* fix mqtt retransmit IP address #602
|
||||||
|
* added debug infos for `scheduler` (web -> `/debug` as trigger prints list of tickers to serial console)
|
||||||
|
|
||||||
## 0.5.73
|
## 0.5.73
|
||||||
* improved payload handling (request / retransmit) #464
|
* improved payload handling (request / retransmit) #464
|
||||||
* included alarm ID parse to serial console (in development)
|
* included alarm ID parse to serial console (in development)
|
||||||
|
|
45
src/app.cpp
45
src/app.cpp
|
@ -3,11 +3,6 @@
|
||||||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
|
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#if defined(ESP32) && defined(F)
|
|
||||||
#undef F
|
|
||||||
#define F(sl) (sl)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include "utils/sun.h"
|
#include "utils/sun.h"
|
||||||
|
@ -43,7 +38,7 @@ void app::setup() {
|
||||||
|
|
||||||
mWifi.setup(mConfig, &mTimestamp, std::bind(&app::onWifi, this, std::placeholders::_1));
|
mWifi.setup(mConfig, &mTimestamp, std::bind(&app::onWifi, this, std::placeholders::_1));
|
||||||
#if !defined(AP_ONLY)
|
#if !defined(AP_ONLY)
|
||||||
everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi));
|
everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mSys->addInverters(&mConfig->inst);
|
mSys->addInverters(&mConfig->inst);
|
||||||
|
@ -136,48 +131,49 @@ void app::onWifi(bool gotIp) {
|
||||||
regularTickers(); // reinstall regular tickers
|
regularTickers(); // reinstall regular tickers
|
||||||
if (gotIp) {
|
if (gotIp) {
|
||||||
mInnerLoopCb = std::bind(&app::loopStandard, this);
|
mInnerLoopCb = std::bind(&app::loopStandard, this);
|
||||||
mSendTickerId = every(std::bind(&app::tickSend, this), mConfig->nrf.sendInterval);
|
mSendTickerId = every(std::bind(&app::tickSend, this), mConfig->nrf.sendInterval, "tSend");
|
||||||
mMqttReconnect = true;
|
mMqttReconnect = true;
|
||||||
once(std::bind(&app::tickNtpUpdate, this), 2);
|
once(std::bind(&app::tickNtpUpdate, this), 2, "ntp2");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mInnerLoopCb = std::bind(&app::loopWifi, this);
|
mInnerLoopCb = std::bind(&app::loopWifi, this);
|
||||||
everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi));
|
everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void app::regularTickers(void) {
|
void app::regularTickers(void) {
|
||||||
DPRINTLN(DBG_DEBUG, F("regularTickers"));
|
DPRINTLN(DBG_DEBUG, F("regularTickers"));
|
||||||
everySec(std::bind(&WebType::tickSecond, &mWeb));
|
everySec(std::bind(&WebType::tickSecond, &mWeb), "webSc");
|
||||||
// Plugins
|
// Plugins
|
||||||
#if defined(ENA_NOKIA) || defined(ENA_SSD1306) || defined(ENA_SH1106)
|
#if defined(ENA_NOKIA) || defined(ENA_SSD1306) || defined(ENA_SH1106)
|
||||||
everySec(std::bind(&MonoDisplayType::tickerSecond, &mMonoDisplay));
|
everySec(std::bind(&MonoDisplayType::tickerSecond, &mMonoDisplay));
|
||||||
#endif
|
#endif
|
||||||
every(std::bind(&PubSerialType::tick, &mPubSerial), mConfig->serial.interval);
|
every(std::bind(&PubSerialType::tick, &mPubSerial), mConfig->serial.interval, "uart");
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void app::tickNtpUpdate(void) {
|
void app::tickNtpUpdate(void) {
|
||||||
uint32_t nxtTrig = 5; // default: check again in 5 sec
|
uint32_t nxtTrig = 5; // default: check again in 5 sec
|
||||||
if (mWifi.getNtpTime()) {
|
if (mWifi.getNtpTime(&nxtTrig)) {
|
||||||
if (mMqttReconnect && mMqttEnabled) {
|
if (mMqttReconnect && mMqttEnabled) {
|
||||||
mMqtt.connect();
|
mMqtt.connect();
|
||||||
everySec(std::bind(&PubMqttType::tickerSecond, &mMqtt));
|
everySec(std::bind(&PubMqttType::tickerSecond, &mMqtt), "mqttS");
|
||||||
everyMin(std::bind(&PubMqttType::tickerMinute, &mMqtt));
|
everyMin(std::bind(&PubMqttType::tickerMinute, &mMqtt), "mqttM");
|
||||||
uint32_t nxtTrig = mTimestamp - ((mTimestamp - 1) % 86400) + 86400; // next midnight
|
uint32_t nxtTrig = mTimestamp - ((mTimestamp - 1) % 86400) + 86400; // next midnight
|
||||||
if(mConfig->mqtt.rstYieldMidNight)
|
if(mConfig->mqtt.rstYieldMidNight)
|
||||||
onceAt(std::bind(&app::tickMidnight, this), nxtTrig);
|
onceAt(std::bind(&app::tickMidnight, this), nxtTrig, "midNi");
|
||||||
mMqttReconnect = false;
|
mMqttReconnect = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nxtTrig = 43200; // check again in 12 h
|
nxtTrig = 43200;
|
||||||
|
|
||||||
if((mSunrise == 0) && (mConfig->sun.lat) && (mConfig->sun.lon)) {
|
if((mSunrise == 0) && (mConfig->sun.lat) && (mConfig->sun.lon)) {
|
||||||
mCalculatedTimezoneOffset = (int8_t)((mConfig->sun.lon >= 0 ? mConfig->sun.lon + 7.5 : mConfig->sun.lon - 7.5) / 15) * 3600;
|
mCalculatedTimezoneOffset = (int8_t)((mConfig->sun.lon >= 0 ? mConfig->sun.lon + 7.5 : mConfig->sun.lon - 7.5) / 15) * 3600;
|
||||||
tickCalcSunrise();
|
tickCalcSunrise();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
once(std::bind(&app::tickNtpUpdate, this), nxtTrig);
|
once(std::bind(&app::tickNtpUpdate, this), nxtTrig, "ntp");
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -191,7 +187,7 @@ void app::tickCalcSunrise(void) {
|
||||||
tickIVCommunication();
|
tickIVCommunication();
|
||||||
|
|
||||||
uint32_t nxtTrig = mSunset + mConfig->sun.offsetSec + 60; // set next trigger to communication stop, +60 for safety that it is certain past communication stop
|
uint32_t nxtTrig = mSunset + mConfig->sun.offsetSec + 60; // set next trigger to communication stop, +60 for safety that it is certain past communication stop
|
||||||
onceAt(std::bind(&app::tickCalcSunrise, this), nxtTrig);
|
onceAt(std::bind(&app::tickCalcSunrise, this), nxtTrig, "Sunri");
|
||||||
if (mMqttEnabled)
|
if (mMqttEnabled)
|
||||||
tickSun();
|
tickSun();
|
||||||
}
|
}
|
||||||
|
@ -212,7 +208,7 @@ void app::tickIVCommunication(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nxtTrig != 0)
|
if (nxtTrig != 0)
|
||||||
onceAt(std::bind(&app::tickIVCommunication, this), nxtTrig);
|
onceAt(std::bind(&app::tickIVCommunication, this), nxtTrig, "ivCom");
|
||||||
}
|
}
|
||||||
if (mMqttEnabled)
|
if (mMqttEnabled)
|
||||||
tickComm();
|
tickComm();
|
||||||
|
@ -222,14 +218,14 @@ void app::tickIVCommunication(void) {
|
||||||
void app::tickSun(void) {
|
void app::tickSun(void) {
|
||||||
// only used and enabled by MQTT (see setup())
|
// only used and enabled by MQTT (see setup())
|
||||||
if (!mMqtt.tickerSun(mSunrise, mSunset, mConfig->sun.offsetSec, mConfig->sun.disNightCom))
|
if (!mMqtt.tickerSun(mSunrise, mSunset, mConfig->sun.offsetSec, mConfig->sun.disNightCom))
|
||||||
once(std::bind(&app::tickSun, this), 1); // MQTT not connected, retry
|
once(std::bind(&app::tickSun, this), 1, "mqSun"); // MQTT not connected, retry
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void app::tickComm(void) {
|
void app::tickComm(void) {
|
||||||
// only used and enabled by MQTT (see setup())
|
// only used and enabled by MQTT (see setup())
|
||||||
if (!mMqtt.tickerComm(!mIVCommunicationOn))
|
if (!mMqtt.tickerComm(!mIVCommunicationOn))
|
||||||
once(std::bind(&app::tickComm, this), 1); // MQTT not connected, retry
|
once(std::bind(&app::tickComm, this), 1, "mqCom"); // MQTT not connected, retry
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -268,7 +264,7 @@ void app::tickSend(void) {
|
||||||
void app::tickMidnight(void) {
|
void app::tickMidnight(void) {
|
||||||
// only used and enabled by MQTT (see setup())
|
// only used and enabled by MQTT (see setup())
|
||||||
uint32_t nxtTrig = mTimestamp - ((mTimestamp - 1) % 86400) + 86400; // next midnight
|
uint32_t nxtTrig = mTimestamp - ((mTimestamp - 1) % 86400) + 86400; // next midnight
|
||||||
onceAt(std::bind(&app::tickMidnight, this), nxtTrig);
|
onceAt(std::bind(&app::tickMidnight, this), nxtTrig, "mid2");
|
||||||
|
|
||||||
mMqtt.tickerMidnight();
|
mMqtt.tickerMidnight();
|
||||||
}
|
}
|
||||||
|
@ -285,8 +281,6 @@ void app::resetSystem(void) {
|
||||||
|
|
||||||
#ifdef AP_ONLY
|
#ifdef AP_ONLY
|
||||||
mTimestamp = 1;
|
mTimestamp = 1;
|
||||||
#else
|
|
||||||
mTimestamp = 0;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mSunrise = 0;
|
mSunrise = 0;
|
||||||
|
@ -329,8 +323,7 @@ void app::updateLed(void) {
|
||||||
if(mConfig->led.led0 != 0xff) {
|
if(mConfig->led.led0 != 0xff) {
|
||||||
Inverter<> *iv = mSys->getInverterByPos(0);
|
Inverter<> *iv = mSys->getInverterByPos(0);
|
||||||
if (NULL != iv) {
|
if (NULL != iv) {
|
||||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
if(iv->isProducing(mTimestamp))
|
||||||
if(iv->isProducing(mTimestamp, rec))
|
|
||||||
digitalWrite(mConfig->led.led0, LOW); // LED on
|
digitalWrite(mConfig->led.led0, LOW); // LED on
|
||||||
else
|
else
|
||||||
digitalWrite(mConfig->led.led0, HIGH); // LED off
|
digitalWrite(mConfig->led.led0, HIGH); // LED off
|
||||||
|
|
14
src/app.h
14
src/app.h
|
@ -102,7 +102,7 @@ class app : public IApp, public ah::Scheduler {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setRebootFlag() {
|
void setRebootFlag() {
|
||||||
once(std::bind(&app::tickReboot, this), 3);
|
once(std::bind(&app::tickReboot, this), 3, "rboot");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *getVersion() {
|
const char *getVersion() {
|
||||||
|
@ -126,7 +126,7 @@ class app : public IApp, public ah::Scheduler {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMqttDiscoveryFlag() {
|
void setMqttDiscoveryFlag() {
|
||||||
once(std::bind(&PubMqttType::sendDiscoveryConfig, &mMqtt), 1);
|
once(std::bind(&PubMqttType::sendDiscoveryConfig, &mMqtt), 1, "disCf");
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMqttPowerLimitAck(Inverter<> *iv) {
|
void setMqttPowerLimitAck(Inverter<> *iv) {
|
||||||
|
@ -174,10 +174,16 @@ class app : public IApp, public ah::Scheduler {
|
||||||
getStat(max);
|
getStat(max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getSchedulerNames(void) {
|
||||||
|
printSchedulers();
|
||||||
|
}
|
||||||
|
|
||||||
void setTimestamp(uint32_t newTime) {
|
void setTimestamp(uint32_t newTime) {
|
||||||
DPRINTLN(DBG_DEBUG, F("setTimestamp: ") + String(newTime));
|
DPRINTLN(DBG_DEBUG, F("setTimestamp: ") + String(newTime));
|
||||||
if(0 == newTime)
|
if(0 == newTime) {
|
||||||
mWifi.getNtpTime();
|
uint32_t tmp;
|
||||||
|
mWifi.getNtpTime(&tmp);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
Scheduler::setTimestamp(newTime);
|
Scheduler::setTimestamp(newTime);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ class IApp {
|
||||||
virtual String getTimeStr(uint32_t offset) = 0;
|
virtual String getTimeStr(uint32_t offset) = 0;
|
||||||
virtual uint32_t getTimezoneOffset() = 0;
|
virtual uint32_t getTimezoneOffset() = 0;
|
||||||
virtual void getSchedulerInfo(uint8_t *max) = 0;
|
virtual void getSchedulerInfo(uint8_t *max) = 0;
|
||||||
|
virtual void getSchedulerNames() = 0;
|
||||||
|
|
||||||
virtual bool getRebootRequestState() = 0;
|
virtual bool getRebootRequestState() = 0;
|
||||||
virtual bool getSettingsValid() = 0;
|
virtual bool getSettingsValid() = 0;
|
||||||
|
|
|
@ -162,10 +162,11 @@ class settings {
|
||||||
if(!LittleFS.begin(LITTLFS_FALSE)) {
|
if(!LittleFS.begin(LITTLFS_FALSE)) {
|
||||||
DPRINTLN(DBG_INFO, F(".. format .."));
|
DPRINTLN(DBG_INFO, F(".. format .."));
|
||||||
LittleFS.format();
|
LittleFS.format();
|
||||||
if(LittleFS.begin(LITTLFS_TRUE))
|
if(LittleFS.begin(LITTLFS_TRUE)) {
|
||||||
DPRINTLN(DBG_INFO, F(".. success"));
|
DPRINTLN(DBG_INFO, F(".. success"));
|
||||||
else
|
} else {
|
||||||
DPRINTLN(DBG_INFO, F(".. failed"));
|
DPRINTLN(DBG_INFO, F(".. failed"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
#define VERSION_MAJOR 0
|
#define VERSION_MAJOR 0
|
||||||
#define VERSION_MINOR 5
|
#define VERSION_MINOR 5
|
||||||
#define VERSION_PATCH 73
|
#define VERSION_PATCH 74
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -164,7 +164,7 @@ class Inverter {
|
||||||
if (getFwVersion() == 0)
|
if (getFwVersion() == 0)
|
||||||
enqueCommand<InfoCommand>(InverterDevInform_All); // firmware version
|
enqueCommand<InfoCommand>(InverterDevInform_All); // firmware version
|
||||||
enqueCommand<InfoCommand>(RealTimeRunData_Debug); // live data
|
enqueCommand<InfoCommand>(RealTimeRunData_Debug); // live data
|
||||||
if (actPowerLimit == 0xffff)
|
if ((actPowerLimit == 0xffff) && isConnected)
|
||||||
enqueCommand<InfoCommand>(SystemConfigPara); // power limit info
|
enqueCommand<InfoCommand>(SystemConfigPara); // power limit info
|
||||||
}
|
}
|
||||||
return _commandQueue.front().get()->getCmd();
|
return _commandQueue.front().get()->getCmd();
|
||||||
|
@ -220,9 +220,11 @@ class Inverter {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setDevControlRequest() {
|
bool setDevControlRequest(uint8_t cmd) {
|
||||||
if(isConnected)
|
if(isConnected) {
|
||||||
mDevControlRequest = true;
|
mDevControlRequest = true;
|
||||||
|
devControlCmd = cmd;
|
||||||
|
}
|
||||||
return isConnected;
|
return isConnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,16 +335,23 @@ class Inverter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAvailable(uint32_t timestamp, record_t<> *rec) {
|
bool isAvailable(uint32_t timestamp) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:isAvailable"));
|
if((timestamp - recordMeas.ts) < INACT_THRES_SEC)
|
||||||
return ((timestamp - rec->ts) < INACT_THRES_SEC);
|
return true;
|
||||||
|
if((timestamp - recordInfo.ts) < INACT_THRES_SEC)
|
||||||
|
return true;
|
||||||
|
if((timestamp - recordConfig.ts) < INACT_THRES_SEC)
|
||||||
|
return true;
|
||||||
|
if((timestamp - recordAlarm.ts) < INACT_THRES_SEC)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isProducing(uint32_t timestamp, record_t<> *rec) {
|
bool isProducing(uint32_t timestamp) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:isProducing"));
|
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:isProducing"));
|
||||||
if(isAvailable(timestamp, rec)) {
|
if(isAvailable(timestamp)) {
|
||||||
uint8_t pos = getPosByChFld(CH0, FLD_PAC, rec);
|
uint8_t pos = getPosByChFld(CH0, FLD_PAC, &recordMeas);
|
||||||
return (getValue(pos, rec) > INACT_PWR_THRESH);
|
return (getValue(pos, &recordMeas) > INACT_PWR_THRESH);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,7 @@ class HmRadio {
|
||||||
mRxLoopCnt = RF_LOOP_CNT;
|
mRxLoopCnt = RF_LOOP_CNT;
|
||||||
|
|
||||||
mSendCnt = 0;
|
mSendCnt = 0;
|
||||||
|
mRetransmits = 0;
|
||||||
|
|
||||||
mSerialDebug = false;
|
mSerialDebug = false;
|
||||||
mIrqRcvd = false;
|
mIrqRcvd = false;
|
||||||
|
@ -194,7 +195,7 @@ class HmRadio {
|
||||||
return mRfChLst[mTxChIdx];
|
return mRfChLst[mTxChIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data) {
|
void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data, bool isRetransmit) {
|
||||||
DPRINTLN(DBG_INFO, F("sendControlPacket cmd: 0x") + String(cmd, HEX));
|
DPRINTLN(DBG_INFO, F("sendControlPacket cmd: 0x") + String(cmd, HEX));
|
||||||
sendCmdPacket(invId, TX_REQ_DEVCONTROL, SINGLE_FRAME, false);
|
sendCmdPacket(invId, TX_REQ_DEVCONTROL, SINGLE_FRAME, false);
|
||||||
uint8_t cnt = 0;
|
uint8_t cnt = 0;
|
||||||
|
@ -215,12 +216,12 @@ class HmRadio {
|
||||||
// crc over all
|
// crc over all
|
||||||
mTxBuf[10 + cnt] = ah::crc8(mTxBuf, 10 + cnt);
|
mTxBuf[10 + cnt] = ah::crc8(mTxBuf, 10 + cnt);
|
||||||
|
|
||||||
sendPacket(invId, mTxBuf, 10 + cnt + 1, true);
|
sendPacket(invId, mTxBuf, 10 + cnt + 1, isRetransmit, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendTimePacket(uint64_t invId, uint8_t cmd, uint32_t ts, uint16_t alarmMesId) {
|
void sendTimePacket(uint64_t invId, uint8_t cmd, uint32_t ts, uint16_t alarmMesId, bool isRetransmit) {
|
||||||
DPRINTLN(DBG_DEBUG, F("sendTimePacket 0x") + String(cmd, HEX));
|
DPRINTLN(DBG_DEBUG, F("sendTimePacket 0x") + String(cmd, HEX));
|
||||||
sendCmdPacket(invId, TX_REQ_INFO, ALL_FRAMES, false);
|
sendCmdPacket(invId, TX_REQ_INFO, ALL_FRAMES, isRetransmit, false);
|
||||||
mTxBuf[10] = cmd; // cid
|
mTxBuf[10] = cmd; // cid
|
||||||
mTxBuf[11] = 0x00;
|
mTxBuf[11] = 0x00;
|
||||||
CP_U32_LittleEndian(&mTxBuf[12], ts);
|
CP_U32_LittleEndian(&mTxBuf[12], ts);
|
||||||
|
@ -233,10 +234,10 @@ class HmRadio {
|
||||||
mTxBuf[25] = (crc ) & 0xff;
|
mTxBuf[25] = (crc ) & 0xff;
|
||||||
mTxBuf[26] = ah::crc8(mTxBuf, 26);
|
mTxBuf[26] = ah::crc8(mTxBuf, 26);
|
||||||
|
|
||||||
sendPacket(invId, mTxBuf, 27, true);
|
sendPacket(invId, mTxBuf, 27, isRetransmit, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendCmdPacket(uint64_t invId, uint8_t mid, uint8_t pid, bool calcCrc = true) {
|
void sendCmdPacket(uint64_t invId, uint8_t mid, uint8_t pid, bool isRetransmit, bool calcCrc = true) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("sendCmdPacket, mid: ") + String(mid, HEX) + F(" pid: ") + String(pid, HEX));
|
DPRINTLN(DBG_VERBOSE, F("sendCmdPacket, mid: ") + String(mid, HEX) + F(" pid: ") + String(pid, HEX));
|
||||||
memset(mTxBuf, 0, MAX_RF_PAYLOAD_SIZE);
|
memset(mTxBuf, 0, MAX_RF_PAYLOAD_SIZE);
|
||||||
mTxBuf[0] = mid; // message id
|
mTxBuf[0] = mid; // message id
|
||||||
|
@ -245,7 +246,7 @@ class HmRadio {
|
||||||
mTxBuf[9] = pid;
|
mTxBuf[9] = pid;
|
||||||
if(calcCrc) {
|
if(calcCrc) {
|
||||||
mTxBuf[10] = ah::crc8(mTxBuf, 10);
|
mTxBuf[10] = ah::crc8(mTxBuf, 10);
|
||||||
sendPacket(invId, mTxBuf, 11, false);
|
sendPacket(invId, mTxBuf, 11, isRetransmit, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,11 +309,12 @@ class HmRadio {
|
||||||
|
|
||||||
|
|
||||||
uint32_t mSendCnt;
|
uint32_t mSendCnt;
|
||||||
|
uint32_t mRetransmits;
|
||||||
|
|
||||||
bool mSerialDebug;
|
bool mSerialDebug;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void sendPacket(uint64_t invId, uint8_t buf[], uint8_t len, bool clear=false) {
|
void sendPacket(uint64_t invId, uint8_t buf[], uint8_t len, bool isRetransmit, bool clear=false) {
|
||||||
//DPRINTLN(DBG_VERBOSE, F("hmRadio.h:sendPacket"));
|
//DPRINTLN(DBG_VERBOSE, F("hmRadio.h:sendPacket"));
|
||||||
//DPRINTLN(DBG_VERBOSE, "sent packet: #" + String(mSendCnt));
|
//DPRINTLN(DBG_VERBOSE, "sent packet: #" + String(mSendCnt));
|
||||||
//dumpBuf("SEN ", buf, len);
|
//dumpBuf("SEN ", buf, len);
|
||||||
|
@ -347,7 +349,10 @@ class HmRadio {
|
||||||
mNrf24.startListening();
|
mNrf24.startListening();
|
||||||
|
|
||||||
RESTORE_IRQ;
|
RESTORE_IRQ;
|
||||||
mSendCnt++;
|
if(isRetransmit)
|
||||||
|
mRetransmits++;
|
||||||
|
else
|
||||||
|
mSendCnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getTxNxtChannel(void) {
|
uint8_t getTxNxtChannel(void) {
|
||||||
|
|
|
@ -103,14 +103,14 @@ class Payload : public Handler<payloadListenerType> {
|
||||||
if (iv->getDevControlRequest()) {
|
if (iv->getDevControlRequest()) {
|
||||||
if (mSerialDebug)
|
if (mSerialDebug)
|
||||||
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Devcontrol request 0x") + String(iv->devControlCmd, HEX) + F(" power limit ") + String(iv->powerLimit[0]));
|
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Devcontrol request 0x") + String(iv->devControlCmd, HEX) + F(" power limit ") + String(iv->powerLimit[0]));
|
||||||
mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit);
|
mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false);
|
||||||
mPayload[iv->id].txCmd = iv->devControlCmd;
|
mPayload[iv->id].txCmd = iv->devControlCmd;
|
||||||
//iv->clearCmdQueue();
|
//iv->clearCmdQueue();
|
||||||
//iv->enqueCommand<InfoCommand>(SystemConfigPara); // read back power limit
|
//iv->enqueCommand<InfoCommand>(SystemConfigPara); // read back power limit
|
||||||
} else {
|
} else {
|
||||||
uint8_t cmd = iv->getQueuedCmd();
|
uint8_t cmd = iv->getQueuedCmd();
|
||||||
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket")); // + String(cmd, HEX));
|
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket")); // + String(cmd, HEX));
|
||||||
mSys->Radio.sendTimePacket(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex);
|
mSys->Radio.sendTimePacket(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false);
|
||||||
mPayload[iv->id].txCmd = cmd;
|
mPayload[iv->id].txCmd = cmd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,9 @@ class Payload : public Handler<payloadListenerType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mPayload[iv->id].complete) {
|
if (!mPayload[iv->id].complete) {
|
||||||
if (!build(iv->id)) { // payload not complete
|
bool crcPass, pyldComplete;
|
||||||
|
crcPass = build(iv->id, &pyldComplete);
|
||||||
|
if (!crcPass && !pyldComplete) { // payload not complete
|
||||||
if ((mPayload[iv->id].requested) && (retransmit)) {
|
if ((mPayload[iv->id].requested) && (retransmit)) {
|
||||||
if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) {
|
if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) {
|
||||||
// This is required to prevent retransmissions without answer.
|
// This is required to prevent retransmissions without answer.
|
||||||
|
@ -185,7 +187,7 @@ class Payload : public Handler<payloadListenerType> {
|
||||||
mPayload[iv->id].retransmits = mMaxRetrans;
|
mPayload[iv->id].retransmits = mMaxRetrans;
|
||||||
} else if(iv->devControlCmd == ActivePowerContr) {
|
} else if(iv->devControlCmd == ActivePowerContr) {
|
||||||
DPRINTLN(DBG_INFO, F("retransmit power limit"));
|
DPRINTLN(DBG_INFO, F("retransmit power limit"));
|
||||||
mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit);
|
mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true);
|
||||||
} else {
|
} else {
|
||||||
if (mPayload[iv->id].retransmits < mMaxRetrans) {
|
if (mPayload[iv->id].retransmits < mMaxRetrans) {
|
||||||
mPayload[iv->id].retransmits++;
|
mPayload[iv->id].retransmits++;
|
||||||
|
@ -193,12 +195,12 @@ class Payload : public Handler<payloadListenerType> {
|
||||||
DPRINTLN(DBG_WARN, F("nothing received: Request Complete Retransmit"));
|
DPRINTLN(DBG_WARN, F("nothing received: Request Complete Retransmit"));
|
||||||
mPayload[iv->id].txCmd = iv->getQueuedCmd();
|
mPayload[iv->id].txCmd = iv->getQueuedCmd();
|
||||||
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket 0x") + String(mPayload[iv->id].txCmd, HEX));
|
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket 0x") + String(mPayload[iv->id].txCmd, HEX));
|
||||||
mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex);
|
mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true);
|
||||||
} else {
|
} else {
|
||||||
for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) {
|
for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) {
|
||||||
if (mPayload[iv->id].len[i] == 0) {
|
if (mPayload[iv->id].len[i] == 0) {
|
||||||
DPRINTLN(DBG_WARN, F("Frame ") + String(i + 1) + F(" missing: Request Retransmit"));
|
DPRINTLN(DBG_WARN, F("Frame ") + String(i + 1) + F(" missing: Request Retransmit"));
|
||||||
mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, (SINGLE_FRAME + i), true);
|
mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, (SINGLE_FRAME + i), true, true);
|
||||||
break; // only request retransmit one frame per loop
|
break; // only request retransmit one frame per loop
|
||||||
}
|
}
|
||||||
yield();
|
yield();
|
||||||
|
@ -208,6 +210,14 @@ class Payload : public Handler<payloadListenerType> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if(!crcPass && pyldComplete) { // crc error on complete Payload
|
||||||
|
if (mPayload[iv->id].retransmits < mMaxRetrans) {
|
||||||
|
mPayload[iv->id].retransmits++;
|
||||||
|
DPRINTLN(DBG_WARN, F("CRC Error: Request Complete Retransmit"));
|
||||||
|
mPayload[iv->id].txCmd = iv->getQueuedCmd();
|
||||||
|
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket 0x") + String(mPayload[iv->id].txCmd, HEX));
|
||||||
|
mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true);
|
||||||
|
}
|
||||||
} else { // payload complete
|
} else { // payload complete
|
||||||
DPRINTLN(DBG_INFO, F("procPyld: cmd: 0x") + String(mPayload[iv->id].txCmd, HEX));
|
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_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX));
|
||||||
|
@ -269,12 +279,21 @@ class Payload : public Handler<payloadListenerType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool build(uint8_t id) {
|
bool build(uint8_t id, bool *complete) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("build"));
|
DPRINTLN(DBG_VERBOSE, F("build"));
|
||||||
uint16_t crc = 0xffff, crcRcv = 0x0000;
|
uint16_t crc = 0xffff, crcRcv = 0x0000;
|
||||||
if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES)
|
if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES)
|
||||||
mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES;
|
mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES;
|
||||||
|
|
||||||
|
// check if all fragments are there
|
||||||
|
*complete = true;
|
||||||
|
for (uint8_t i = 0; i < mPayload[id].maxPackId; i++) {
|
||||||
|
if(mPayload[id].len[i] == 0)
|
||||||
|
*complete = false;
|
||||||
|
}
|
||||||
|
if(!*complete)
|
||||||
|
return false;
|
||||||
|
|
||||||
for (uint8_t i = 0; i < mPayload[id].maxPackId; i++) {
|
for (uint8_t i = 0; i < mPayload[id].maxPackId; i++) {
|
||||||
if (mPayload[id].len[i] > 0) {
|
if (mPayload[id].len[i] > 0) {
|
||||||
if (i == (mPayload[id].maxPackId - 1)) {
|
if (i == (mPayload[id].maxPackId - 1)) {
|
||||||
|
|
|
@ -45,7 +45,6 @@ class PubMqtt {
|
||||||
mVersion = version;
|
mVersion = version;
|
||||||
mSys = sys;
|
mSys = sys;
|
||||||
mUtcTimestamp = utcTs;
|
mUtcTimestamp = utcTs;
|
||||||
mExeOnce = true;
|
|
||||||
mIntervalTimeout = 1;
|
mIntervalTimeout = 1;
|
||||||
|
|
||||||
snprintf(mLwtTopic, MQTT_TOPIC_LEN + 5, "%s/mqtt", mCfgMqtt->topic);
|
snprintf(mLwtTopic, MQTT_TOPIC_LEN + 5, "%s/mqtt", mCfgMqtt->topic);
|
||||||
|
@ -243,12 +242,9 @@ class PubMqtt {
|
||||||
void onConnect(bool sessionPreset) {
|
void onConnect(bool sessionPreset) {
|
||||||
DPRINTLN(DBG_INFO, F("MQTT connected"));
|
DPRINTLN(DBG_INFO, F("MQTT connected"));
|
||||||
|
|
||||||
if(mExeOnce) {
|
publish("version", mVersion, true);
|
||||||
publish("version", mVersion, true);
|
publish("device", mDevName, true);
|
||||||
publish("device", mDevName, true);
|
publish("ip_addr", WiFi.localIP().toString().c_str(), true);
|
||||||
publish("ip_addr", WiFi.localIP().toString().c_str(), true);
|
|
||||||
mExeOnce = false;
|
|
||||||
}
|
|
||||||
tickerMinute();
|
tickerMinute();
|
||||||
publish(mLwtTopic, mLwtOnline, true, false);
|
publish(mLwtTopic, mLwtOnline, true, false);
|
||||||
|
|
||||||
|
@ -381,7 +377,7 @@ class PubMqtt {
|
||||||
|
|
||||||
// inverter status
|
// inverter status
|
||||||
uint8_t status = MQTT_STATUS_AVAIL_PROD;
|
uint8_t status = MQTT_STATUS_AVAIL_PROD;
|
||||||
if ((!iv->isAvailable(*mUtcTimestamp, rec)) || (!iv->config->enabled)) {
|
if ((!iv->isAvailable(*mUtcTimestamp)) || (!iv->config->enabled)) {
|
||||||
status = MQTT_STATUS_NOT_AVAIL_NOT_PROD;
|
status = MQTT_STATUS_NOT_AVAIL_NOT_PROD;
|
||||||
if(iv->config->enabled) { // only change all-avail if inverter is enabled!
|
if(iv->config->enabled) { // only change all-avail if inverter is enabled!
|
||||||
totalComplete = false;
|
totalComplete = false;
|
||||||
|
@ -390,7 +386,7 @@ class PubMqtt {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mIvAvail = true;
|
mIvAvail = true;
|
||||||
if (!iv->isProducing(*mUtcTimestamp, rec)) {
|
if (!iv->isProducing(*mUtcTimestamp)) {
|
||||||
if (MQTT_STATUS_AVAIL_PROD == status)
|
if (MQTT_STATUS_AVAIL_PROD == status)
|
||||||
status = MQTT_STATUS_AVAIL_NOT_PROD;
|
status = MQTT_STATUS_AVAIL_NOT_PROD;
|
||||||
}
|
}
|
||||||
|
@ -566,7 +562,6 @@ class PubMqtt {
|
||||||
subscriptionCb mSubscriptionCb;
|
subscriptionCb mSubscriptionCb;
|
||||||
bool mIvAvail; // shows if at least one inverter is available
|
bool mIvAvail; // shows if at least one inverter is available
|
||||||
uint8_t mLastIvState[MAX_NUM_INVERTERS];
|
uint8_t mLastIvState[MAX_NUM_INVERTERS];
|
||||||
bool mExeOnce;
|
|
||||||
uint16_t mIntervalTimeout;
|
uint16_t mIntervalTimeout;
|
||||||
|
|
||||||
// last will topic and payload must be available trough lifetime of 'espMqttClient'
|
// last will topic and payload must be available trough lifetime of 'espMqttClient'
|
||||||
|
|
|
@ -28,8 +28,8 @@ class PubSerial {
|
||||||
Inverter<> *iv = mSys->getInverterByPos(id);
|
Inverter<> *iv = mSys->getInverterByPos(id);
|
||||||
if (NULL != iv) {
|
if (NULL != iv) {
|
||||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||||
if (iv->isAvailable(*mUtcTimestamp, rec)) {
|
if (iv->isAvailable(*mUtcTimestamp)) {
|
||||||
DPRINTLN(DBG_INFO, F("Inverter: ") + String(id));
|
DPRINTLN(DBG_INFO, "Iv: " + String(id));
|
||||||
for (uint8_t i = 0; i < rec->length; i++) {
|
for (uint8_t i = 0; i < rec->length; i++) {
|
||||||
if (0.0f != iv->getValue(i, rec)) {
|
if (0.0f != iv->getValue(i, rec)) {
|
||||||
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, iv->getFieldName(i, rec));
|
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, iv->getFieldName(i, rec));
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#ifndef __DBG_H__
|
#ifndef __DBG_H__
|
||||||
#define __DBG_H__
|
#define __DBG_H__
|
||||||
#if defined(ESP32) && defined(F)
|
#if defined(F) //defined(ESP32) &&
|
||||||
#undef F
|
#undef F
|
||||||
#define F(sl) (sl)
|
#define F(sl) (sl)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,8 +20,9 @@ namespace ah {
|
||||||
uint32_t timeout;
|
uint32_t timeout;
|
||||||
uint32_t reload;
|
uint32_t reload;
|
||||||
bool isTimestamp;
|
bool isTimestamp;
|
||||||
sP() : c(NULL), timeout(0), reload(0), isTimestamp(false) {}
|
char name[6];
|
||||||
sP(scdCb a, uint32_t tmt, uint32_t rl, bool its) : c(a), timeout(tmt), reload(rl), isTimestamp(its) {}
|
sP() : c(NULL), timeout(0), reload(0), isTimestamp(false), name("\n") {}
|
||||||
|
sP(scdCb a, uint32_t tmt, uint32_t rl, bool its) : c(a), timeout(tmt), reload(rl), isTimestamp(its), name("\n") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_NUM_TICKER 30
|
#define MAX_NUM_TICKER 30
|
||||||
|
@ -64,15 +65,15 @@ namespace ah {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void once(scdCb c, uint32_t timeout) { addTicker(c, timeout, 0, false); }
|
void once(scdCb c, uint32_t timeout, const char *name) { addTicker(c, timeout, 0, false, name); }
|
||||||
void onceAt(scdCb c, uint32_t timestamp) { addTicker(c, timestamp, 0, true); }
|
void onceAt(scdCb c, uint32_t timestamp, const char *name) { addTicker(c, timestamp, 0, true, name); }
|
||||||
uint8_t every(scdCb c, uint32_t interval){ return addTicker(c, interval, interval, false); }
|
uint8_t every(scdCb c, uint32_t interval, const char *name){ return addTicker(c, interval, interval, false, name); }
|
||||||
|
|
||||||
void everySec(scdCb c) { every(c, SCD_SEC); }
|
void everySec(scdCb c, const char *name) { every(c, SCD_SEC, name); }
|
||||||
void everyMin(scdCb c) { every(c, SCD_MIN); }
|
void everyMin(scdCb c, const char *name) { every(c, SCD_MIN, name); }
|
||||||
void everyHour(scdCb c) { every(c, SCD_HOUR); }
|
void everyHour(scdCb c, const char *name) { every(c, SCD_HOUR, name); }
|
||||||
void every12h(scdCb c) { every(c, SCD_12H); }
|
void every12h(scdCb c, const char *name) { every(c, SCD_12H, name); }
|
||||||
void everyDay(scdCb c) { every(c, SCD_DAY); }
|
void everyDay(scdCb c, const char *name) { every(c, SCD_DAY, name); }
|
||||||
|
|
||||||
virtual void setTimestamp(uint32_t ts) {
|
virtual void setTimestamp(uint32_t ts) {
|
||||||
mTimestamp = ts;
|
mTimestamp = ts;
|
||||||
|
@ -102,11 +103,19 @@ namespace ah {
|
||||||
*max = mMax;
|
*max = mMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void printSchedulers() {
|
||||||
|
for (uint8_t i = 0; i < MAX_NUM_TICKER; i++) {
|
||||||
|
if (mTickerInUse[i]) {
|
||||||
|
DPRINTLN(DBG_INFO, String(mTicker[i].name) + ", tmt: " + String(mTicker[i].timeout) + ", rel: " + String(mTicker[i].reload));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint32_t mTimestamp;
|
uint32_t mTimestamp;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline uint8_t addTicker(scdCb c, uint32_t timeout, uint32_t reload, bool isTimestamp) {
|
inline uint8_t addTicker(scdCb c, uint32_t timeout, uint32_t reload, bool isTimestamp, const char *name) {
|
||||||
for (uint8_t i = 0; i < MAX_NUM_TICKER; i++) {
|
for (uint8_t i = 0; i < MAX_NUM_TICKER; i++) {
|
||||||
if (!mTickerInUse[i]) {
|
if (!mTickerInUse[i]) {
|
||||||
mTickerInUse[i] = true;
|
mTickerInUse[i] = true;
|
||||||
|
@ -114,6 +123,8 @@ namespace ah {
|
||||||
mTicker[i].timeout = timeout;
|
mTicker[i].timeout = timeout;
|
||||||
mTicker[i].reload = reload;
|
mTicker[i].reload = reload;
|
||||||
mTicker[i].isTimestamp = isTimestamp;
|
mTicker[i].isTimestamp = isTimestamp;
|
||||||
|
memset(mTicker[i].name, 0, 6);
|
||||||
|
strncpy(mTicker[i].name, name, (strlen(name) < 6) ? strlen(name) : 5);
|
||||||
if(mMax == i)
|
if(mMax == i)
|
||||||
mMax = i + 1;
|
mMax = i + 1;
|
||||||
return i;
|
return i;
|
||||||
|
|
|
@ -14,6 +14,11 @@
|
||||||
|
|
||||||
#include "../appInterface.h"
|
#include "../appInterface.h"
|
||||||
|
|
||||||
|
#if defined(F) //defined(ESP32) &&
|
||||||
|
#undef F
|
||||||
|
#define F(sl) (sl)
|
||||||
|
#endif
|
||||||
|
|
||||||
template<class HMSYSTEM>
|
template<class HMSYSTEM>
|
||||||
class RestApi {
|
class RestApi {
|
||||||
public:
|
public:
|
||||||
|
@ -265,6 +270,7 @@ class RestApi {
|
||||||
obj[F("rx_fail_answer")] = stat->rxFailNoAnser;
|
obj[F("rx_fail_answer")] = stat->rxFailNoAnser;
|
||||||
obj[F("frame_cnt")] = stat->frmCnt;
|
obj[F("frame_cnt")] = stat->frmCnt;
|
||||||
obj[F("tx_cnt")] = mSys->Radio.mSendCnt;
|
obj[F("tx_cnt")] = mSys->Radio.mSendCnt;
|
||||||
|
obj[F("retransmits")] = mSys->Radio.mRetransmits;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getInverterList(JsonObject obj) {
|
void getInverterList(JsonObject obj) {
|
||||||
|
@ -413,8 +419,8 @@ class RestApi {
|
||||||
invObj[F("id")] = i;
|
invObj[F("id")] = i;
|
||||||
invObj[F("name")] = String(iv->config->name);
|
invObj[F("name")] = String(iv->config->name);
|
||||||
invObj[F("version")] = String(iv->getFwVersion());
|
invObj[F("version")] = String(iv->getFwVersion());
|
||||||
invObj[F("is_avail")] = iv->isAvailable(mApp->getTimestamp(), rec);
|
invObj[F("is_avail")] = iv->isAvailable(mApp->getTimestamp());
|
||||||
invObj[F("is_producing")] = iv->isProducing(mApp->getTimestamp(), rec);
|
invObj[F("is_producing")] = iv->isProducing(mApp->getTimestamp());
|
||||||
invObj[F("ts_last_success")] = iv->getLastTs(rec);
|
invObj[F("ts_last_success")] = iv->getLastTs(rec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -546,13 +552,10 @@ class RestApi {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(F("power") == jsonIn[F("cmd")]) {
|
if(F("power") == jsonIn[F("cmd")])
|
||||||
iv->devControlCmd = (jsonIn[F("val")] == 1) ? TurnOn : TurnOff;
|
accepted = iv->setDevControlRequest((jsonIn[F("val")] == 1) ? TurnOn : TurnOff);
|
||||||
accepted = iv->setDevControlRequest();
|
else if(F("restart") == jsonIn[F("restart")])
|
||||||
} else if(F("restart") == jsonIn[F("restart")]) {
|
accepted = iv->setDevControlRequest(Restart);
|
||||||
iv->devControlCmd = Restart;
|
|
||||||
accepted = iv->setDevControlRequest();
|
|
||||||
}
|
|
||||||
else if(0 == strncmp("limit_", jsonIn[F("cmd")].as<const char*>(), 6)) {
|
else if(0 == strncmp("limit_", jsonIn[F("cmd")].as<const char*>(), 6)) {
|
||||||
iv->powerLimit[0] = jsonIn["val"];
|
iv->powerLimit[0] = jsonIn["val"];
|
||||||
if(F("limit_persistent_relative") == jsonIn[F("cmd")])
|
if(F("limit_persistent_relative") == jsonIn[F("cmd")])
|
||||||
|
@ -563,10 +566,8 @@ class RestApi {
|
||||||
iv->powerLimit[1] = RelativNonPersistent;
|
iv->powerLimit[1] = RelativNonPersistent;
|
||||||
else if(F("limit_nonpersistent_absolute") == jsonIn[F("cmd")])
|
else if(F("limit_nonpersistent_absolute") == jsonIn[F("cmd")])
|
||||||
iv->powerLimit[1] = AbsolutNonPersistent;
|
iv->powerLimit[1] = AbsolutNonPersistent;
|
||||||
iv->devControlCmd = ActivePowerContr;
|
|
||||||
accepted = iv->setDevControlRequest();
|
accepted = iv->setDevControlRequest(ActivePowerContr);
|
||||||
if(accepted)
|
|
||||||
mApp->ivSendHighPrio(iv);
|
|
||||||
}
|
}
|
||||||
else if(F("dev") == jsonIn[F("cmd")]) {
|
else if(F("dev") == jsonIn[F("cmd")]) {
|
||||||
DPRINTLN(DBG_INFO, F("dev cmd"));
|
DPRINTLN(DBG_INFO, F("dev cmd"));
|
||||||
|
@ -580,7 +581,8 @@ class RestApi {
|
||||||
if(!accepted) {
|
if(!accepted) {
|
||||||
jsonOut[F("error")] = F("inverter does not accept dev control request at this moment");
|
jsonOut[F("error")] = F("inverter does not accept dev control request at this moment");
|
||||||
return false;
|
return false;
|
||||||
}
|
} else
|
||||||
|
mApp->ivSendHighPrio(iv);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,14 +30,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="wrapper">
|
<div id="wrapper">
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<a class="btn" href="/erase">ERASE SETTINGS (not WiFi)</a>
|
|
||||||
<fieldset>
|
|
||||||
<legend class="des">Upload JSON Settings</legend>
|
|
||||||
<form id="form" method="POST" action="/upload" enctype="multipart/form-data" accept-charset="utf-8">
|
|
||||||
<input type="file" name="upload">
|
|
||||||
<input type="button" class="btn" value="Upload" onclick="hide()">
|
|
||||||
</form>
|
|
||||||
</fieldset>
|
|
||||||
<form method="post" action="/save">
|
<form method="post" action="/save">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend class="des">Device Host Name</legend>
|
<legend class="des">Device Host Name</legend>
|
||||||
|
@ -196,7 +188,15 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="hr mb-3 mt-3"></div>
|
<div class="hr mb-3 mt-3"></div>
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<a href="/get_setup" target="_blank">Download your settings (JSON file)</a> (only saved values, passwords will be removed!)
|
<a class="btn" href="/erase">ERASE SETTINGS (not WiFi)</a>
|
||||||
|
<fieldset>
|
||||||
|
<legend class="des">Upload / Store JSON Settings</legend>
|
||||||
|
<form id="form" method="POST" action="/upload" enctype="multipart/form-data" accept-charset="utf-8">
|
||||||
|
<input type="file" name="upload">
|
||||||
|
<input type="button" class="btn" value="Upload" onclick="hide()">
|
||||||
|
</form>
|
||||||
|
</fieldset>
|
||||||
|
<a class="btn" href="/get_setup" target="_blank">Download settings (JSON file)</a> (only saved values, passwords will be removed!)
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -94,11 +94,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
main.append(
|
main.append(
|
||||||
|
genTabRow("TX count", stat["tx_cnt"]),
|
||||||
genTabRow("RX success", stat["rx_success"]),
|
genTabRow("RX success", stat["rx_success"]),
|
||||||
genTabRow("RX fail", stat["rx_fail"]),
|
genTabRow("RX fail", stat["rx_fail"]),
|
||||||
genTabRow("RX no answer", stat["rx_fail_answer"]),
|
genTabRow("RX no answer", stat["rx_fail_answer"]),
|
||||||
genTabRow("RX frames received", stat["frame_cnt"]),
|
genTabRow("RX fragments", stat["frame_cnt"]),
|
||||||
genTabRow("TX count", stat["tx_cnt"])
|
genTabRow("TX retransmits", stat["retransmits"])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,7 @@ class Web {
|
||||||
mWeb.on("/upload", HTTP_POST, std::bind(&Web::onUpload, this, std::placeholders::_1),
|
mWeb.on("/upload", HTTP_POST, std::bind(&Web::onUpload, this, std::placeholders::_1),
|
||||||
std::bind(&Web::onUpload2, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6));
|
std::bind(&Web::onUpload2, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6));
|
||||||
mWeb.on("/serial", HTTP_GET, std::bind(&Web::onSerial, this, std::placeholders::_1));
|
mWeb.on("/serial", HTTP_GET, std::bind(&Web::onSerial, this, std::placeholders::_1));
|
||||||
|
mWeb.on("/debug", HTTP_GET, std::bind(&Web::onDebug, this, std::placeholders::_1));
|
||||||
|
|
||||||
|
|
||||||
mEvts.onConnect(std::bind(&Web::onConnect, this, std::placeholders::_1));
|
mEvts.onConnect(std::bind(&Web::onConnect, this, std::placeholders::_1));
|
||||||
|
@ -189,12 +190,15 @@ class Web {
|
||||||
msg.replace("\r\n", "<rn>");
|
msg.replace("\r\n", "<rn>");
|
||||||
if(mSerialAddTime) {
|
if(mSerialAddTime) {
|
||||||
if((9 + mSerialBufFill) <= WEB_SERIAL_BUF_SIZE) {
|
if((9 + mSerialBufFill) <= WEB_SERIAL_BUF_SIZE) {
|
||||||
strncpy(&mSerialBuf[mSerialBufFill], mApp->getTimeStr(mApp->getTimezoneOffset()).c_str(), 9);
|
if(mApp->getTimestamp() > 0) {
|
||||||
mSerialBufFill += 9;
|
strncpy(&mSerialBuf[mSerialBufFill], mApp->getTimeStr(mApp->getTimezoneOffset()).c_str(), 9);
|
||||||
|
mSerialBufFill += 9;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mSerialBufFill = 0;
|
mSerialBufFill = 0;
|
||||||
mEvts.send("webSerial, buffer overflow!", "serial", millis());
|
mEvts.send("webSerial, buffer overflow!<rn>", "serial", millis());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
mSerialAddTime = false;
|
mSerialAddTime = false;
|
||||||
}
|
}
|
||||||
|
@ -209,7 +213,7 @@ class Web {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mSerialBufFill = 0;
|
mSerialBufFill = 0;
|
||||||
mEvts.send("webSerial, buffer overflow!", "serial", millis());
|
mEvts.send("webSerial, buffer overflow!<rn>", "serial", millis());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,6 +653,12 @@ class Web {
|
||||||
request->send(200, "text/json", "{success:true}");
|
request->send(200, "text/json", "{success:true}");
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
void onDebug(AsyncWebServerRequest *request) {
|
||||||
|
mApp->getSchedulerNames();
|
||||||
|
AsyncWebServerResponse *response = request->beginResponse(200, F("text/html"), "ok");
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
|
|
||||||
void onSerial(AsyncWebServerRequest *request) {
|
void onSerial(AsyncWebServerRequest *request) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("onSerial"));
|
DPRINTLN(DBG_VERBOSE, F("onSerial"));
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
// NTP CONFIG
|
// NTP CONFIG
|
||||||
#define NTP_PACKET_SIZE 48
|
#define NTP_PACKET_SIZE 48
|
||||||
|
#define NTP_RETRIES 5
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
ahoywifi::ahoywifi() : mApIp(192, 168, 4, 1) {}
|
ahoywifi::ahoywifi() : mApIp(192, 168, 4, 1) {}
|
||||||
|
@ -26,6 +26,7 @@ void ahoywifi::setup(settings_t *config, uint32_t *utcTimestamp, appWifiCb cb) {
|
||||||
mStaConn = DISCONNECTED;
|
mStaConn = DISCONNECTED;
|
||||||
mCnt = 0;
|
mCnt = 0;
|
||||||
mScanActive = false;
|
mScanActive = false;
|
||||||
|
mRetries = NTP_RETRIES;
|
||||||
|
|
||||||
#if defined(ESP8266)
|
#if defined(ESP8266)
|
||||||
wifiConnectHandler = WiFi.onStationModeConnected(std::bind(&ahoywifi::onConnect, this, std::placeholders::_1));
|
wifiConnectHandler = WiFi.onStationModeConnected(std::bind(&ahoywifi::onConnect, this, std::placeholders::_1));
|
||||||
|
@ -148,7 +149,17 @@ void ahoywifi::setupStation(void) {
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
bool ahoywifi::getNtpTime(void) {
|
bool ahoywifi::getNtpTime(uint32_t *nxtTrig) {
|
||||||
|
if(0 != mRetries) {
|
||||||
|
DPRINTLN(DBG_INFO, "try to getNtpTime");
|
||||||
|
*nxtTrig = 43200; // check again in 12h (if NTP was successful)
|
||||||
|
mRetries--;
|
||||||
|
} else if(0 != *mUtcTimestamp) { // time is availabe, but NTP not
|
||||||
|
*nxtTrig = 5; // check again 5s
|
||||||
|
mRetries = NTP_RETRIES;
|
||||||
|
return true; // true is necessary to enable all timers even if NTP was not reachable
|
||||||
|
}
|
||||||
|
|
||||||
if(GOT_IP != mStaConn)
|
if(GOT_IP != mStaConn)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -267,6 +278,7 @@ void ahoywifi::connectionEvent(WiFiStatus_t status) {
|
||||||
setupWifi(); // reconnect with AP / Station setup
|
setupWifi(); // reconnect with AP / Station setup
|
||||||
mAppWifiCb(false);
|
mAppWifiCb(false);
|
||||||
DPRINTLN(DBG_INFO, "[WiFi] Connection Lost");
|
DPRINTLN(DBG_INFO, "[WiFi] Connection Lost");
|
||||||
|
mRetries = NTP_RETRIES;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ class ahoywifi {
|
||||||
|
|
||||||
void setup(settings_t *config, uint32_t *utcTimestamp, appWifiCb cb);
|
void setup(settings_t *config, uint32_t *utcTimestamp, appWifiCb cb);
|
||||||
void tickWifiLoop(void);
|
void tickWifiLoop(void);
|
||||||
bool getNtpTime(void);
|
bool getNtpTime(uint32_t *nxtTrig);
|
||||||
void scanAvailNetworks(void);
|
void scanAvailNetworks(void);
|
||||||
void getAvailNetworks(JsonObject obj);
|
void getAvailNetworks(JsonObject obj);
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@ class ahoywifi {
|
||||||
|
|
||||||
uint8_t mLoopCnt;
|
uint8_t mLoopCnt;
|
||||||
bool mScanActive;
|
bool mScanActive;
|
||||||
|
uint8_t mRetries;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*__AHOYWIFI_H__*/
|
#endif /*__AHOYWIFI_H__*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue