mirror of
https://github.com/lumapu/ahoy.git
synced 2025-06-01 10:11:37 +02:00
0.7.46
* removed `delay` from ePaper * started improvements of `/system` * fix LEDs to check all configured inverters
This commit is contained in:
parent
201098ae0b
commit
f3192b49ab
16 changed files with 218 additions and 124 deletions
|
@ -1,5 +1,10 @@
|
|||
# Development Changes
|
||||
|
||||
## 0.7.46 - 2023-09-01
|
||||
* removed `delay` from ePaper
|
||||
* started improvements of `/system`
|
||||
* fix LEDs to check all configured inverters
|
||||
|
||||
## 0.7.45 - 2023-08-29
|
||||
* change ePaper text to symbols PR #1131
|
||||
* added some invertes to dev info list #1111
|
||||
|
|
20
src/app.cpp
20
src/app.cpp
|
@ -567,11 +567,11 @@ void app::mqttSubRxCb(JsonObject obj) {
|
|||
void app::setupLed(void) {
|
||||
uint8_t led_off = (mConfig->led.led_high_active) ? LOW : HIGH;
|
||||
|
||||
if (mConfig->led.led0 != 0xff) {
|
||||
if (mConfig->led.led0 != DEF_PIN_OFF) {
|
||||
pinMode(mConfig->led.led0, OUTPUT);
|
||||
digitalWrite(mConfig->led.led0, led_off);
|
||||
}
|
||||
if (mConfig->led.led1 != 0xff) {
|
||||
if (mConfig->led.led1 != DEF_PIN_OFF) {
|
||||
pinMode(mConfig->led.led1, OUTPUT);
|
||||
digitalWrite(mConfig->led.led1, led_off);
|
||||
}
|
||||
|
@ -582,17 +582,23 @@ void app::updateLed(void) {
|
|||
uint8_t led_off = (mConfig->led.led_high_active) ? LOW : HIGH;
|
||||
uint8_t led_on = (mConfig->led.led_high_active) ? HIGH : LOW;
|
||||
|
||||
if (mConfig->led.led0 != 0xff) {
|
||||
Inverter<> *iv = mSys.getInverterByPos(0);
|
||||
if (mConfig->led.led0 != DEF_PIN_OFF) {
|
||||
Inverter<> *iv;
|
||||
for (uint8_t id = 0; id < mSys.getNumInverters(); id++) {
|
||||
iv = mSys.getInverterByPos(id);
|
||||
if (NULL != iv) {
|
||||
if (iv->isProducing())
|
||||
if (iv->isProducing()) {
|
||||
// turn on when at least one inverter is producing
|
||||
digitalWrite(mConfig->led.led0, led_on);
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if(iv->config->enabled)
|
||||
digitalWrite(mConfig->led.led0, led_off);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mConfig->led.led1 != 0xff) {
|
||||
if (mConfig->led.led1 != DEF_PIN_OFF) {
|
||||
if (getMqttIsConnected()) {
|
||||
digitalWrite(mConfig->led.led1, led_on);
|
||||
} else {
|
||||
|
|
|
@ -273,6 +273,7 @@ class app : public IApp, public ah::Scheduler {
|
|||
#endif
|
||||
if(mConfig->plugin.display.type != 0)
|
||||
mDisplay.payloadEventListener(cmd);
|
||||
updateLed();
|
||||
}
|
||||
|
||||
void mqttSubRxCb(JsonObject obj);
|
||||
|
|
|
@ -728,8 +728,8 @@ const byteAssign_t InfoAssignment[] = {
|
|||
*/
|
||||
|
||||
void reset(uint8_t id, bool clrSts = false) {
|
||||
DPRINT_IVID(DBG_INFO, id);
|
||||
DBGPRINTLN(F("resetPayload"));
|
||||
//DPRINT_IVID(DBG_INFO, id);
|
||||
//DBGPRINTLN(F("resetPayload"));
|
||||
memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES);
|
||||
mPayload[id].gotFragment = false;
|
||||
/*mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES;
|
||||
|
|
|
@ -26,6 +26,7 @@ class CmtRadio {
|
|||
public:
|
||||
CmtRadio() {
|
||||
mDtuSn = DTU_SN;
|
||||
mCmtAvail = false;
|
||||
}
|
||||
|
||||
void setup(uint8_t pinCsb, uint8_t pinFcsb, bool genDtuSn = true) {
|
||||
|
@ -63,6 +64,10 @@ class CmtRadio {
|
|||
mSerialDebug = true;
|
||||
}
|
||||
|
||||
bool cmtIsAvail() {
|
||||
return mCmtAvail;
|
||||
}
|
||||
|
||||
void sendControlPacket(const uint64_t *ivId, uint8_t cmd, uint16_t *data, bool isRetransmit) {
|
||||
DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x"));
|
||||
DBGHEXLN(cmd);
|
||||
|
@ -143,10 +148,14 @@ class CmtRadio {
|
|||
inline void reset(bool genDtuSn) {
|
||||
if(genDtuSn)
|
||||
generateDtuSn();
|
||||
if(!mCmt.reset())
|
||||
if(!mCmt.reset()) {
|
||||
mCmtAvail = false;
|
||||
DPRINTLN(DBG_WARN, F("Initializing CMT2300A failed!"));
|
||||
else
|
||||
}
|
||||
else {
|
||||
mCmtAvail = true;
|
||||
mCmt.goRx();
|
||||
}
|
||||
|
||||
mSendCnt = 0;
|
||||
mRetransmits = 0;
|
||||
|
@ -208,6 +217,7 @@ class CmtRadio {
|
|||
bool mSerialDebug;
|
||||
bool mIrqRcvd;
|
||||
bool mRqstGetRx;
|
||||
bool mCmtAvail;
|
||||
};
|
||||
|
||||
#endif /*__HMS_RADIO_H__*/
|
||||
|
|
|
@ -127,8 +127,6 @@ monitor_filters =
|
|||
platform = espressif32@6.3.2
|
||||
board = esp32-s3-devkitc-1
|
||||
upload_protocol = esp-builtin
|
||||
debug_tool = esp-builtin
|
||||
debug_speed = 12000
|
||||
build_flags = ${env.build_flags}
|
||||
-DDEF_NRF_CS_PIN=37
|
||||
-DDEF_NRF_CE_PIN=38
|
||||
|
@ -142,5 +140,7 @@ build_flags = ${env.build_flags}
|
|||
-DDEF_LED0=18
|
||||
-DDEF_LED1=17
|
||||
-DLED_ACTIVE_HIGH
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
monitor_filters =
|
||||
esp32_exception_decoder
|
||||
esp32_exception_decoder, colorize
|
||||
|
|
|
@ -61,11 +61,14 @@ class Display {
|
|||
if (mMono != NULL)
|
||||
mMono->loop();
|
||||
|
||||
if (mNewPayload || ((++mLoopCnt % 10) == 0)) {
|
||||
if (mNewPayload || (((++mLoopCnt) % 30) == 0)) {
|
||||
mNewPayload = false;
|
||||
mLoopCnt = 0;
|
||||
DataScreen();
|
||||
}
|
||||
#if defined(ESP32)
|
||||
mEpaper.tickerSecond();
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -102,13 +105,10 @@ class Display {
|
|||
}
|
||||
#if defined(ESP32)
|
||||
else if (mCfg->type == 10) {
|
||||
|
||||
mEpaper.loop(totalPower, totalYieldDay, totalYieldTotal, isprod);
|
||||
mRefreshCycle++;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(ESP32)
|
||||
if (mRefreshCycle > 480) {
|
||||
mEpaper.fullRefresh();
|
||||
mRefreshCycle = 0;
|
||||
|
|
|
@ -21,10 +21,14 @@ DisplayEPaper::DisplayEPaper() {
|
|||
mHeadFootPadding = 16;
|
||||
}
|
||||
|
||||
|
||||
//***************************************************************************
|
||||
void DisplayEPaper::init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, uint8_t _BUSY, uint8_t _SCK, uint8_t _MOSI, uint32_t *utcTs, const char *version) {
|
||||
mUtcTs = utcTs;
|
||||
|
||||
mRefreshState = RefreshStatus::LOGO;
|
||||
mSecondCnt = 0;
|
||||
|
||||
if (type == 10) {
|
||||
Serial.begin(115200);
|
||||
_display = new GxEPD2_BW<GxEPD2_150_BN, GxEPD2_150_BN::HEIGHT>(GxEPD2_150_BN(_CS, _DC, _RST, _BUSY));
|
||||
|
@ -38,26 +42,7 @@ void DisplayEPaper::init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, u
|
|||
_display->init(115200, true, 20, false);
|
||||
_display->setRotation(mDisplayRotation);
|
||||
_display->setFullWindow();
|
||||
|
||||
// Logo
|
||||
_display->fillScreen(GxEPD_BLACK);
|
||||
_display->drawBitmap(0, 0, logo, 200, 200, GxEPD_WHITE);
|
||||
while (_display->nextPage())
|
||||
;
|
||||
|
||||
// clean the screen
|
||||
delay(2000);
|
||||
_display->fillScreen(GxEPD_WHITE);
|
||||
while (_display->nextPage())
|
||||
;
|
||||
|
||||
headlineIP();
|
||||
|
||||
_version = version;
|
||||
versionFooter();
|
||||
|
||||
// call the PowerPage to change the PV Power Values
|
||||
actualPowerPaged(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,15 +53,51 @@ void DisplayEPaper::config(uint8_t rotation, bool enPowerSafe) {
|
|||
|
||||
//***************************************************************************
|
||||
void DisplayEPaper::fullRefresh() {
|
||||
// screen complete black
|
||||
if(RefreshStatus::DONE != mRefreshState)
|
||||
return;
|
||||
mSecondCnt = 2;
|
||||
mRefreshState = RefreshStatus::BLACK;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
void DisplayEPaper::refreshLoop() {
|
||||
switch(mRefreshState) {
|
||||
case RefreshStatus::LOGO:
|
||||
_display->fillScreen(GxEPD_BLACK);
|
||||
while (_display->nextPage())
|
||||
;
|
||||
delay(2000);
|
||||
// screen complete white
|
||||
_display->drawBitmap(0, 0, logo, 200, 200, GxEPD_WHITE);
|
||||
mNextRefreshState = RefreshStatus::PARTITIALS;
|
||||
mRefreshState = RefreshStatus::WAIT;
|
||||
break;
|
||||
|
||||
case RefreshStatus::BLACK:
|
||||
_display->fillScreen(GxEPD_BLACK);
|
||||
mNextRefreshState = RefreshStatus::WHITE;
|
||||
mRefreshState = RefreshStatus::WAIT;
|
||||
break;
|
||||
|
||||
case RefreshStatus::WHITE:
|
||||
if(mSecondCnt == 0) {
|
||||
_display->fillScreen(GxEPD_WHITE);
|
||||
while (_display->nextPage())
|
||||
;
|
||||
mNextRefreshState = RefreshStatus::PARTITIALS;
|
||||
mRefreshState = RefreshStatus::WAIT;
|
||||
}
|
||||
break;
|
||||
|
||||
case RefreshStatus::WAIT:
|
||||
if(!_display->nextPage())
|
||||
mRefreshState = mNextRefreshState;
|
||||
break;
|
||||
|
||||
case RefreshStatus::PARTITIALS:
|
||||
headlineIP();
|
||||
versionFooter();
|
||||
mSecondCnt = 4; // display Logo time during boot up
|
||||
mRefreshState = RefreshStatus::DONE;
|
||||
break;
|
||||
|
||||
default: // RefreshStatus::DONE
|
||||
break;
|
||||
}
|
||||
}
|
||||
//***************************************************************************
|
||||
void DisplayEPaper::headlineIP() {
|
||||
|
@ -185,9 +206,8 @@ void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, floa
|
|||
} else if ((totalPower > 0) && (totalPower <= 9999)) {
|
||||
snprintf(_fmtText, sizeof(_fmtText), "%.0f W", totalPower);
|
||||
_changed = true;
|
||||
} else {
|
||||
} else
|
||||
snprintf(_fmtText, sizeof(_fmtText), "offline");
|
||||
}
|
||||
|
||||
if ((totalPower == 0) && (mEnPowerSafe)) {
|
||||
_display->fillRect(0, mHeadFootPadding, 200, 200, GxEPD_BLACK);
|
||||
|
@ -200,57 +220,43 @@ void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, floa
|
|||
|
||||
if ((totalYieldDay > 0) && (totalYieldTotal > 0)) {
|
||||
// Today Production
|
||||
bool kwh = (totalYieldDay > 9999);
|
||||
if(kwh)
|
||||
snprintf(_fmtText, _display->width(), "%.1f", (totalYieldDay / 1000));
|
||||
else
|
||||
snprintf(_fmtText, _display->width(), "%.0f", (totalYieldDay));
|
||||
|
||||
_display->setFont(&FreeSans18pt7b);
|
||||
y = _display->height() / 2;
|
||||
_display->setCursor(5, y);
|
||||
|
||||
if (totalYieldDay > 9999) {
|
||||
snprintf(_fmtText, _display->width(), "%.1f", (totalYieldDay / 1000));
|
||||
_display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh);
|
||||
_display->drawInvertedBitmap(5, y - ((tbh + 30) / 2), myToday, 30, 30, GxEPD_BLACK);
|
||||
_display->drawInvertedBitmap(5, ((kwh) ? (y - ((tbh + 30) / 2)) : (y - tbh)), myToday, 30, 30, GxEPD_BLACK);
|
||||
x = ((_display->width() - tbw - 20) / 2) - tbx;
|
||||
_display->setCursor(x, y);
|
||||
_display->print(_fmtText);
|
||||
_display->setCursor(_display->width() - 50, y);
|
||||
_display->setCursor(_display->width() - ((kwh) ? 50 : 38), y);
|
||||
_display->setFont(&FreeSans12pt7b);
|
||||
_display->println("kWh");
|
||||
} else if (totalYieldDay <= 9999) {
|
||||
snprintf(_fmtText, _display->width(), "%.0f", (totalYieldDay));
|
||||
_display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh);
|
||||
_display->drawInvertedBitmap(5, y - tbh, myToday, 30, 30, GxEPD_BLACK);
|
||||
x = ((_display->width() - tbw - 20) / 2) - tbx;
|
||||
_display->setCursor(x, y);
|
||||
_display->print(_fmtText);
|
||||
_display->setCursor(_display->width() - 38, y);
|
||||
_display->setFont(&FreeSans12pt7b);
|
||||
_display->println("Wh");
|
||||
}
|
||||
_display->println((kwh) ? "kWh" : "Wh");
|
||||
y = y + tbh + 15;
|
||||
|
||||
|
||||
// Total Production
|
||||
bool mwh = (totalYieldTotal > 9999);
|
||||
if(mwh)
|
||||
snprintf(_fmtText, _display->width(), "%.1f", (totalYieldTotal / 1000));
|
||||
else
|
||||
snprintf(_fmtText, _display->width(), "%.0f", (totalYieldTotal));
|
||||
|
||||
_display->setFont(&FreeSans18pt7b);
|
||||
_display->setCursor(5, y);
|
||||
if (totalYieldTotal > 9999) {
|
||||
snprintf(_fmtText, _display->width(), "%.1f", (totalYieldTotal / 1000));
|
||||
_display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh);
|
||||
_display->drawInvertedBitmap(5, y - tbh, mySigma, 30, 30, GxEPD_BLACK);
|
||||
x = ((_display->width() - tbw - 20) / 2) - tbx;
|
||||
_display->setCursor(x, y);
|
||||
_display->print(_fmtText);
|
||||
_display->setCursor(_display->width() - 59, y);
|
||||
_display->setCursor(_display->width() - ((mwh) ? 59 : 50), y);
|
||||
_display->setFont(&FreeSans12pt7b);
|
||||
_display->println("MWh");
|
||||
} else if (totalYieldTotal <= 9999) {
|
||||
snprintf(_fmtText, _display->width(), "%.0f", (totalYieldTotal));
|
||||
_display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh);
|
||||
_display->drawInvertedBitmap(5, y - tbh, mySigma, 30, 30, GxEPD_BLACK);
|
||||
x = ((_display->width() - tbw - 20) / 2) - tbx;
|
||||
_display->setCursor(x, y);
|
||||
_display->print(_fmtText);
|
||||
_display->setCursor(_display->width() - 50, y);
|
||||
_display->setFont(&FreeSans12pt7b);
|
||||
_display->println("kWh");
|
||||
}
|
||||
_display->println((mwh) ? "MWh" : "kWh");
|
||||
}
|
||||
|
||||
// Inverter online
|
||||
|
@ -263,14 +269,18 @@ void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, floa
|
|||
_display->setCursor(x, y);
|
||||
_display->println(_fmtText);
|
||||
}
|
||||
yield();
|
||||
} while (_display->nextPage());
|
||||
}
|
||||
//***************************************************************************
|
||||
void DisplayEPaper::loop(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) {
|
||||
if(RefreshStatus::DONE != mRefreshState)
|
||||
return;
|
||||
|
||||
// check if the IP has changed
|
||||
if (_settedIP != WiFi.localIP().toString().c_str()) {
|
||||
if (_settedIP != WiFi.localIP().toString()) {
|
||||
// save the new IP and call the Headline Function to adapt the Headline
|
||||
_settedIP = WiFi.localIP().toString().c_str();
|
||||
_settedIP = WiFi.localIP().toString();
|
||||
headlineIP();
|
||||
}
|
||||
|
||||
|
@ -286,5 +296,11 @@ void DisplayEPaper::loop(float totalPower, float totalYieldDay, float totalYield
|
|||
|
||||
_display->powerOff();
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
void DisplayEPaper::tickerSecond() {
|
||||
if(mSecondCnt != 0)
|
||||
mSecondCnt--;
|
||||
refreshLoop();
|
||||
}
|
||||
#endif // ESP32
|
||||
|
|
|
@ -30,6 +30,8 @@ class DisplayEPaper {
|
|||
void init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, uint8_t _BUSY, uint8_t _SCK, uint8_t _MOSI, uint32_t* utcTs, const char* version);
|
||||
void config(uint8_t rotation, bool enPowerSafe);
|
||||
void loop(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod);
|
||||
void refreshLoop();
|
||||
void tickerSecond();
|
||||
|
||||
private:
|
||||
void headlineIP();
|
||||
|
@ -38,15 +40,26 @@ class DisplayEPaper {
|
|||
void offlineFooter();
|
||||
void versionFooter();
|
||||
|
||||
enum class RefreshStatus : uint8_t {
|
||||
DONE,
|
||||
BLACK,
|
||||
WHITE,
|
||||
WAIT,
|
||||
PARTITIALS,
|
||||
LOGO
|
||||
};
|
||||
|
||||
uint8_t mDisplayRotation;
|
||||
bool _changed = false;
|
||||
char _fmtText[35];
|
||||
const char* _settedIP;
|
||||
String _settedIP;
|
||||
uint8_t mHeadFootPadding;
|
||||
GxEPD2_GFX* _display;
|
||||
uint32_t* mUtcTs;
|
||||
bool mEnPowerSafe;
|
||||
const char* _version;
|
||||
RefreshStatus mRefreshState, mNextRefreshState;
|
||||
uint8_t mSecondCnt;
|
||||
};
|
||||
|
||||
#endif // ESP32
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
--success: #009900;
|
||||
|
||||
--input-bg: #eee;
|
||||
--table-border: #ccc;
|
||||
|
||||
--nav-bg: #333;
|
||||
--primary: #006ec0;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
--success: #00bb00;
|
||||
|
||||
--input-bg: #333;
|
||||
--table-border: #333;
|
||||
|
||||
--nav-bg: #333;
|
||||
--primary: #004d87;
|
||||
|
|
|
@ -329,7 +329,7 @@ th {
|
|||
|
||||
.table td, .table th {
|
||||
padding: .75rem;
|
||||
border-bottom: 1px solid var(--nav-bg);
|
||||
border-bottom: 1px solid var(--table-border);
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
|
@ -737,3 +737,30 @@ h5 {
|
|||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.badge-success {
|
||||
color: #fff;
|
||||
background-color: #28a745;
|
||||
}
|
||||
|
||||
.badge-warning {
|
||||
color: #212529;
|
||||
background-color: #ffc107;
|
||||
}
|
||||
|
||||
.badge-error {
|
||||
color: #fff;
|
||||
background-color: #dc3545;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: .25em .4em;
|
||||
font-size: 75%;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: baseline;
|
||||
border-radius: .25rem;
|
||||
}
|
||||
|
|
|
@ -49,33 +49,47 @@
|
|||
}
|
||||
}
|
||||
|
||||
function badge(success, text) {
|
||||
return ml("span", {class: "badge badge-" + ((success) ? "success" : "error")}, text);
|
||||
}
|
||||
|
||||
function headline(text) {
|
||||
return ml("div", {class: "head p-2 mt-3"}, ml("div", {class: "row"}, ml("div", {class: "col a-c"}, text)))
|
||||
}
|
||||
|
||||
function tr(val1, val2) {
|
||||
if(typeof val2 == "number")
|
||||
val2 = String(val2);
|
||||
return ml("tr", {}, [
|
||||
ml("th", {}, val1),
|
||||
ml("td", {}, val2)
|
||||
]);
|
||||
}
|
||||
|
||||
function parseRadio(obj, stat) {
|
||||
const pa = ["MIN (recommended)", "LOW", "HIGH", "MAX"];
|
||||
const datarate = ["1 MBps", "2 MBps", "250 kbps"];
|
||||
|
||||
var main = document.getElementById("radio");
|
||||
var h = div(["head", "p-2"]);
|
||||
var r = div(["row"]);
|
||||
r.appendChild(div(["col", "a-c"], "Radio"));
|
||||
h.appendChild(r);
|
||||
main.appendChild(h);
|
||||
document.getElementById("radio").append(
|
||||
headline("NRF Radio"),
|
||||
ml("table", {class: "table"}, [
|
||||
ml("tbody", {}, [
|
||||
tr("NRF24L01", badge(obj.isconnected, ((obj.isconnected) ? "" : "not ") + "connected")),
|
||||
tr("Power Level", pa[obj.power_level])
|
||||
])
|
||||
]),
|
||||
|
||||
main.appendChild(
|
||||
genTabRow("nrf24l01" + (obj["isPVariant"] ? "+ " : ""), (obj["isconnected"] ? "is connected " : "is not connected "))
|
||||
);
|
||||
|
||||
if(obj["isconnected"]) {
|
||||
main.appendChild(genTabRow("Datarate", datarate[obj["DataRate"]]));
|
||||
main.appendChild(genTabRow("Power Level", pa[obj["power_level"]]));
|
||||
}
|
||||
|
||||
main.append(
|
||||
genTabRow("TX count", stat["tx_cnt"]),
|
||||
genTabRow("RX success", stat["rx_success"]),
|
||||
genTabRow("RX fail", stat["rx_fail"]),
|
||||
genTabRow("RX no answer", stat["rx_fail_answer"]),
|
||||
genTabRow("RX fragments", stat["frame_cnt"]),
|
||||
genTabRow("TX retransmits", stat["retransmits"])
|
||||
headline("Statistics"),
|
||||
ml("table", {class: "table"}, [
|
||||
ml("tbody", {}, [
|
||||
tr("TX count", stat.tx_cnt),
|
||||
tr("RX success", stat.rx_success),
|
||||
tr("RX fail", stat.rx_fail),
|
||||
tr("RX no answer", stat.rx_fail_answer),
|
||||
tr("RX fragments", stat.frame_cnt),
|
||||
tr("TX retransmits", stat.retransmits)
|
||||
])
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue