Browse Source

0.7.46

* removed `delay` from ePaper
* started improvements of `/system`
* fix LEDs to check all configured inverters
pull/1148/head
lumapu 1 year ago
parent
commit
f3192b49ab
  1. 5
      src/CHANGES.md
  2. 26
      src/app.cpp
  3. 1
      src/app.h
  4. 4
      src/hm/miPayload.h
  5. 16
      src/hms/hmsRadio.h
  6. 6
      src/platformio.ini
  7. 8
      src/plugins/Display/Display.h
  8. 2
      src/plugins/Display/Display_Mono_64X48.h
  9. 2
      src/plugins/Display/Display_Mono_84X48.h
  10. 166
      src/plugins/Display/Display_ePaper.cpp
  11. 15
      src/plugins/Display/Display_ePaper.h
  12. 2
      src/web/RestApi.h
  13. 1
      src/web/html/colorBright.css
  14. 1
      src/web/html/colorDark.css
  15. 29
      src/web/html/style.css
  16. 58
      src/web/html/system.html

5
src/CHANGES.md

@ -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

26
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 (NULL != iv) {
if (iv->isProducing())
digitalWrite(mConfig->led.led0, led_on);
else
digitalWrite(mConfig->led.led0, led_off);
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()) {
// turn on when at least one inverter is producing
digitalWrite(mConfig->led.led0, led_on);
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 {

1
src/app.h

@ -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);

4
src/hm/miPayload.h

@ -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;

16
src/hms/hmsRadio.h

@ -25,7 +25,8 @@ class CmtRadio {
typedef Cmt2300a<SpiType> CmtType;
public:
CmtRadio() {
mDtuSn = DTU_SN;
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__*/

6
src/platformio.ini

@ -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

8
src/plugins/Display/Display.h

@ -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;

2
src/plugins/Display/Display_Mono_64X48.h

@ -50,7 +50,7 @@ class DisplayMono64X48 : public DisplayMono {
void loop(void) {
if (mEnPowerSafe) {
if (mTimeout != 0)
mTimeout--;
mTimeout--;
}
}

2
src/plugins/Display/Display_Mono_84X48.h

@ -50,7 +50,7 @@ class DisplayMono84X48 : public DisplayMono {
void loop(void) {
if (mEnPowerSafe) {
if (mTimeout != 0)
mTimeout--;
mTimeout--;
}
}

166
src/plugins/Display/Display_ePaper.cpp

@ -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
_display->fillScreen(GxEPD_BLACK);
while (_display->nextPage())
;
delay(2000);
// screen complete white
_display->fillScreen(GxEPD_WHITE);
while (_display->nextPage())
;
if(RefreshStatus::DONE != mRefreshState)
return;
mSecondCnt = 2;
mRefreshState = RefreshStatus::BLACK;
}
//***************************************************************************
void DisplayEPaper::refreshLoop() {
switch(mRefreshState) {
case RefreshStatus::LOGO:
_display->fillScreen(GxEPD_BLACK);
_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);
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);
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");
} 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->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh);
_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() - ((kwh) ? 50 : 38), y);
_display->setFont(&FreeSans12pt7b);
_display->println((kwh) ? "kWh" : "Wh");
y = y + tbh + 15;
// Total Production
_display->setFont(&FreeSans18pt7b);
_display->setCursor(5, y);
if (totalYieldTotal > 9999) {
bool mwh = (totalYieldTotal > 9999);
if(mwh)
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->setFont(&FreeSans12pt7b);
_display->println("MWh");
} else if (totalYieldTotal <= 9999) {
else
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->setFont(&FreeSans18pt7b);
_display->setCursor(5, y);
_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() - ((mwh) ? 59 : 50), y);
_display->setFont(&FreeSans12pt7b);
_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

15
src/plugins/Display/Display_ePaper.h

@ -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

2
src/web/RestApi.h

@ -224,7 +224,7 @@ class RestApi {
#endif /* !defined(ETHERNET) */
obj[F("device_name")] = mConfig->sys.deviceName;
obj[F("dark_mode")] = (bool)mConfig->sys.darkMode;
obj[F("sched_reboot")] = (bool)mConfig->sys.schedReboot;
obj[F("sched_reboot")] = (bool)mConfig->sys.schedReboot;
obj[F("mac")] = WiFi.macAddress();
obj[F("hostname")] = mConfig->sys.deviceName;

1
src/web/html/colorBright.css

@ -8,6 +8,7 @@
--success: #009900;
--input-bg: #eee;
--table-border: #ccc;
--nav-bg: #333;
--primary: #006ec0;

1
src/web/html/colorDark.css

@ -8,6 +8,7 @@
--success: #00bb00;
--input-bg: #333;
--table-border: #333;
--nav-bg: #333;
--primary: #004d87;

29
src/web/html/style.css

@ -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;
}

58
src/web/html/system.html

@ -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);
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"]]));
}
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.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…
Cancel
Save