Merge remote-tracking branch 'tbnobody/OpenDTU/master' into development
This commit is contained in:
commit
367e0f9b6e
@ -7,7 +7,10 @@
|
||||
|
||||
#define CHART_HEIGHT 20 // chart area hight in pixels
|
||||
#define CHART_WIDTH 47 // chart area width in pixels
|
||||
#define DIAG_POSX 80 // position were Diag is drawn at
|
||||
|
||||
// Left-Upper position of diagram is drawn
|
||||
// (text of Y-axis is display left of that pos)
|
||||
#define DIAG_POSX 80
|
||||
#define DIAG_POSY 0
|
||||
|
||||
class DisplayGraphicDiagramClass {
|
||||
@ -15,7 +18,7 @@ public:
|
||||
DisplayGraphicDiagramClass();
|
||||
|
||||
void init(Scheduler& scheduler, U8G2* display);
|
||||
void redraw();
|
||||
void redraw(uint8_t screenSaverOffsetX);
|
||||
|
||||
void updatePeriod();
|
||||
|
||||
@ -34,6 +37,4 @@ private:
|
||||
|
||||
float _iRunningAverage = 0;
|
||||
uint16_t _iRunningAverageCnt = 0;
|
||||
|
||||
uint8_t _graphPosX = DIAG_POSX;
|
||||
};
|
||||
@ -62,7 +62,7 @@ public:
|
||||
bool isValidNrf24Config() const;
|
||||
bool isValidCmt2300Config() const;
|
||||
bool isValidEthConfig() const;
|
||||
bool isValidHuaweiConfig();
|
||||
bool isValidHuaweiConfig() const;
|
||||
|
||||
private:
|
||||
PinMapping_t _pinMapping;
|
||||
|
||||
@ -102,6 +102,9 @@
|
||||
|
||||
#define REACHABLE_THRESHOLD 2U
|
||||
|
||||
#define LED_BRIGHTNESS 100U
|
||||
|
||||
#define MAX_INVERTER_LIMIT 2250
|
||||
#define VEDIRECT_ENABLED false
|
||||
#define VEDIRECT_VERBOSE_LOGGING false
|
||||
#define VEDIRECT_UPDATESONLY true
|
||||
|
||||
@ -34,8 +34,8 @@ public:
|
||||
HoymilesRadio_NRF* getRadioNrf();
|
||||
HoymilesRadio_CMT* getRadioCmt();
|
||||
|
||||
uint32_t PollInterval() const;
|
||||
void setPollInterval(const uint32_t interval);
|
||||
uint32_t PollInterval() const const;
|
||||
void setPollInterval(const const uint32_t interval);
|
||||
void setVerboseLogging(bool verboseLogging);
|
||||
|
||||
bool isAllRadioIdle() const;
|
||||
|
||||
@ -38,6 +38,7 @@ lib_deps =
|
||||
olikraus/U8g2 @ ^2.35.8
|
||||
buelowp/sunset @ ^1.1.7
|
||||
https://github.com/arkhipenko/TaskScheduler#testing
|
||||
https://github.com/arkhipenko/TaskScheduler#testing
|
||||
https://github.com/coryjfowler/MCP_CAN_lib
|
||||
plerup/EspSoftwareSerial@^8.0.1
|
||||
mobizt/FirebaseJson @ ^3.0.6
|
||||
|
||||
@ -161,12 +161,14 @@ void DisplayGraphicClass::loop()
|
||||
if (Datastore.getIsAtLeastOneReachable()) {
|
||||
displayPowerSave = false;
|
||||
if (_isLarge) {
|
||||
_diagram.redraw();
|
||||
uint8_t screenSaverOffsetX = enableScreensaver ? (_mExtra % 7) : 0;
|
||||
_diagram.redraw(screenSaverOffsetX);
|
||||
}
|
||||
if (Datastore.getTotalAcPowerEnabled() > 999) {
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_kw[_display_language], (Datastore.getTotalAcPowerEnabled() / 1000));
|
||||
const float watts = Datastore.getTotalAcPowerEnabled();
|
||||
if (watts > 999) {
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_kw[_display_language], watts / 1000);
|
||||
} else {
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_w[_display_language], Datastore.getTotalAcPowerEnabled());
|
||||
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_w[_display_language], watts);
|
||||
}
|
||||
printText(_fmtText, 0);
|
||||
_previousMillis = millis();
|
||||
|
||||
@ -37,21 +37,17 @@ void DisplayGraphicDiagramClass::averageLoop()
|
||||
|
||||
void DisplayGraphicDiagramClass::dataPointLoop()
|
||||
{
|
||||
if (_graphValuesCount >= CHART_WIDTH) {
|
||||
for (uint8_t i = 0; i < CHART_WIDTH - 1; i++) {
|
||||
if (_graphValuesCount >= std::size(_graphValues)) {
|
||||
for (uint8_t i = 0; i < std::size(_graphValues) - 1; i++) {
|
||||
_graphValues[i] = _graphValues[i + 1];
|
||||
}
|
||||
_graphValuesCount = CHART_WIDTH - 1;
|
||||
_graphValuesCount = std::size(_graphValues) - 1;
|
||||
}
|
||||
if (_iRunningAverageCnt != 0) {
|
||||
_graphValues[_graphValuesCount++] = _iRunningAverage / _iRunningAverageCnt;
|
||||
_iRunningAverage = 0;
|
||||
_iRunningAverageCnt = 0;
|
||||
}
|
||||
|
||||
if (Configuration.get().Display.ScreenSaver) {
|
||||
_graphPosX = DIAG_POSX - (_graphValuesCount % 2);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DisplayGraphicDiagramClass::getSecondsPerDot()
|
||||
@ -64,25 +60,32 @@ void DisplayGraphicDiagramClass::updatePeriod()
|
||||
_dataPointTask.setInterval(getSecondsPerDot() * TASK_SECOND);
|
||||
}
|
||||
|
||||
void DisplayGraphicDiagramClass::redraw()
|
||||
void DisplayGraphicDiagramClass::redraw(uint8_t screenSaverOffsetX)
|
||||
{
|
||||
uint8_t graphPosY = DIAG_POSY;
|
||||
const uint8_t graphPosX = DIAG_POSX + ((screenSaverOffsetX > 3) ? 1 : 0); // screenSaverOffsetX expected to be in range 0..6
|
||||
const uint8_t graphPosY = DIAG_POSY + ((screenSaverOffsetX > 3) ? 1 : 0);
|
||||
|
||||
// draw diagram axis
|
||||
_display->drawVLine(_graphPosX, graphPosY, CHART_HEIGHT);
|
||||
_display->drawHLine(_graphPosX, graphPosY + CHART_HEIGHT - 1, CHART_WIDTH);
|
||||
_display->drawVLine(graphPosX, graphPosY, CHART_HEIGHT);
|
||||
_display->drawHLine(graphPosX, graphPosY + CHART_HEIGHT - 1, CHART_WIDTH);
|
||||
|
||||
_display->drawLine(_graphPosX + 1, graphPosY + 1, _graphPosX + 2, graphPosY + 2); // UP-arrow
|
||||
_display->drawLine(_graphPosX + CHART_WIDTH - 3, graphPosY + CHART_HEIGHT - 3, _graphPosX + CHART_WIDTH - 2, graphPosY + CHART_HEIGHT - 2); // LEFT-arrow
|
||||
_display->drawLine(_graphPosX + CHART_WIDTH - 3, graphPosY + CHART_HEIGHT + 1, _graphPosX + CHART_WIDTH - 2, graphPosY + CHART_HEIGHT); // LEFT-arrow
|
||||
_display->drawLine(graphPosX + 1, graphPosY + 1, graphPosX + 2, graphPosY + 2); // UP-arrow
|
||||
_display->drawLine(graphPosX - 2, graphPosY + 2, graphPosX - 1, graphPosY + 1); // UP-arrow
|
||||
_display->drawLine(graphPosX + CHART_WIDTH - 3, graphPosY + CHART_HEIGHT - 3, graphPosX + CHART_WIDTH - 2, graphPosY + CHART_HEIGHT - 2); // LEFT-arrow
|
||||
_display->drawLine(graphPosX + CHART_WIDTH - 3, graphPosY + CHART_HEIGHT + 1, graphPosX + CHART_WIDTH - 2, graphPosY + CHART_HEIGHT); // LEFT-arrow
|
||||
|
||||
// draw AC value
|
||||
_display->setFont(u8g2_font_tom_thumb_4x6_mr);
|
||||
_display->setFont(u8g2_font_tom_thumb_4x6_mr); // 4 pixels per char
|
||||
char fmtText[7];
|
||||
const float maxWatts = *std::max_element(_graphValues.begin(), _graphValues.end());
|
||||
if (maxWatts > 999) {
|
||||
snprintf(fmtText, sizeof(fmtText), "%2.1fkW", maxWatts / 1000);
|
||||
} else {
|
||||
snprintf(fmtText, sizeof(fmtText), "%dW", static_cast<uint16_t>(maxWatts));
|
||||
}
|
||||
const uint8_t textLength = strlen(fmtText);
|
||||
_display->drawStr(_graphPosX - (textLength * 4), graphPosY + 5, fmtText);
|
||||
const uint8_t space_and_arrow_pixels = 2;
|
||||
_display->drawStr(graphPosX - space_and_arrow_pixels - (textLength * 4), graphPosY + 5, fmtText);
|
||||
|
||||
// draw chart
|
||||
const float scaleFactor = maxWatts / CHART_HEIGHT;
|
||||
@ -90,15 +93,15 @@ void DisplayGraphicDiagramClass::redraw()
|
||||
for (int i = 0; i < _graphValuesCount; i++) {
|
||||
if (scaleFactor > 0) {
|
||||
if (i == 0) {
|
||||
_display->drawPixel(_graphPosX + 1 + i, graphPosY + CHART_HEIGHT - ((_graphValues[i] / scaleFactor) + 0.5)); // + 0.5 to round mathematical
|
||||
_display->drawPixel(graphPosX + 1 + i, graphPosY + CHART_HEIGHT - ((_graphValues[i] / scaleFactor) + 0.5)); // + 0.5 to round mathematical
|
||||
} else {
|
||||
_display->drawLine(_graphPosX + i, graphPosY + CHART_HEIGHT - ((_graphValues[i - 1] / scaleFactor) + 0.5), _graphPosX + 1 + i, graphPosY + CHART_HEIGHT - ((_graphValues[i] / scaleFactor) + 0.5));
|
||||
_display->drawLine(graphPosX + i, graphPosY + CHART_HEIGHT - ((_graphValues[i - 1] / scaleFactor) + 0.5), graphPosX + 1 + i, graphPosY + CHART_HEIGHT - ((_graphValues[i] / scaleFactor) + 0.5));
|
||||
}
|
||||
}
|
||||
|
||||
// draw one tick per hour to the x-axis
|
||||
if (i * getSecondsPerDot() > (3600u * axisTick)) {
|
||||
_display->drawPixel(_graphPosX + 1 + i, graphPosY + CHART_HEIGHT);
|
||||
_display->drawPixel(graphPosX + 1 + i, graphPosY + CHART_HEIGHT);
|
||||
axisTick++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,22 +92,22 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request)
|
||||
}
|
||||
|
||||
JsonObject victronPinObj = curPin.createNestedObject("victron");
|
||||
victronPinObj[F("rx")] = pin.victron_rx;
|
||||
victronPinObj[F("tx")] = pin.victron_tx;
|
||||
victronPinObj["rx"] = pin.victron_rx;
|
||||
victronPinObj["tx"] = pin.victron_tx;
|
||||
|
||||
JsonObject batteryPinObj = curPin.createNestedObject("battery");
|
||||
batteryPinObj[F("rx")] = pin.battery_rx;
|
||||
batteryPinObj[F("rxen")] = pin.battery_rxen;
|
||||
batteryPinObj[F("tx")] = pin.battery_tx;
|
||||
batteryPinObj[F("txen")] = pin.battery_txen;
|
||||
batteryPinObj["rx"] = pin.battery_rx;
|
||||
batteryPinObj["rxen"] = pin.battery_rxen;
|
||||
batteryPinObj["tx"] = pin.battery_tx;
|
||||
batteryPinObj["txen"] = pin.battery_txen;
|
||||
|
||||
JsonObject huaweiPinObj = curPin.createNestedObject("huawei");
|
||||
huaweiPinObj[F("miso")] = pin.huawei_miso;
|
||||
huaweiPinObj[F("mosi")] = pin.huawei_mosi;
|
||||
huaweiPinObj[F("clk")] = pin.huawei_clk;
|
||||
huaweiPinObj[F("irq")] = pin.huawei_irq;
|
||||
huaweiPinObj[F("cs")] = pin.huawei_cs;
|
||||
huaweiPinObj[F("power")] = pin.huawei_power;
|
||||
huaweiPinObj["miso"] = pin.huawei_miso;
|
||||
huaweiPinObj["mosi"] = pin.huawei_mosi;
|
||||
huaweiPinObj["clk"] = pin.huawei_clk;
|
||||
huaweiPinObj["irq"] = pin.huawei_irq;
|
||||
huaweiPinObj["cs"] = pin.huawei_cs;
|
||||
huaweiPinObj["power"] = pin.huawei_power;
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
|
||||
@ -18,6 +18,10 @@ extern const uint8_t file_zones_json_end[] asm("_binary_webapp_dist_zones_json_g
|
||||
extern const uint8_t file_app_js_end[] asm("_binary_webapp_dist_js_app_js_gz_end");
|
||||
extern const uint8_t file_site_webmanifest_end[] asm("_binary_webapp_dist_site_webmanifest_end");
|
||||
|
||||
#ifdef AUTO_GIT_HASH
|
||||
#define ETAG_HTTP_HEADER_VAL "\"" AUTO_GIT_HASH "\"" // ETag value must be between quotes
|
||||
#endif
|
||||
|
||||
void WebApiWebappClass::init(AsyncWebServer& server)
|
||||
{
|
||||
_server = &server;
|
||||
@ -62,12 +66,12 @@ void WebApiWebappClass::init(AsyncWebServer& server)
|
||||
});
|
||||
|
||||
_server->on("/js/app.js", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
#ifdef AUTO_GIT_HASH
|
||||
#ifdef ETAG_HTTP_HEADER_VAL
|
||||
// check client If-None-Match header vs ETag/AUTO_GIT_HASH
|
||||
bool eTagMatch = false;
|
||||
if (request->hasHeader("If-None-Match")) {
|
||||
const AsyncWebHeader* h = request->getHeader("If-None-Match");
|
||||
if (strncmp(AUTO_GIT_HASH, h->value().c_str(), strlen(AUTO_GIT_HASH)) == 0) {
|
||||
if (strncmp(ETAG_HTTP_HEADER_VAL, h->value().c_str(), strlen(ETAG_HTTP_HEADER_VAL)) == 0) {
|
||||
eTagMatch = true;
|
||||
}
|
||||
}
|
||||
@ -82,7 +86,7 @@ void WebApiWebappClass::init(AsyncWebServer& server)
|
||||
}
|
||||
// HTTP requires cache headers in 200 and 304 to be identical
|
||||
response->addHeader("Cache-Control", "public, must-revalidate");
|
||||
response->addHeader("ETag", AUTO_GIT_HASH);
|
||||
response->addHeader("ETag", ETAG_HTTP_HEADER_VAL);
|
||||
#else
|
||||
AsyncWebServerResponse* response = request->beginResponse_P(200, "text/javascript", file_app_js_start, file_app_js_end - file_app_js_start);
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
"vue-router": "^4.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@intlify/unplugin-vue-i18n": "^1.6.0",
|
||||
"@intlify/unplugin-vue-i18n": "^2.0.0",
|
||||
"@rushstack/eslint-patch": "^1.6.1",
|
||||
"@tsconfig/node18": "^18.2.2",
|
||||
"@types/bootstrap": "^5.2.10",
|
||||
@ -41,7 +41,7 @@
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.0.10",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-css-injected-by-js": "^3.3.0",
|
||||
"vue-tsc": "^1.8.25"
|
||||
"vite-plugin-css-injected-by-js": "^3.3.1",
|
||||
"vue-tsc": "^1.8.26"
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,10 +245,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.8.0.tgz#62adf8f6ef67c8eba6cf8d521e248f3503f237d3"
|
||||
integrity sha512-TmgR0RCLjzrSo+W3wT0ALf9851iFMlVI9EYNGeWvZFUQTAJx0bvfsMlPdgVtV1tDNRiAfhkFsMKu6jtUY1ZLKQ==
|
||||
|
||||
"@intlify/unplugin-vue-i18n@^1.6.0":
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/unplugin-vue-i18n/-/unplugin-vue-i18n-1.6.0.tgz#49ab21125c79257e455a6e562a2511c8681b870c"
|
||||
integrity sha512-IGeFNWxdEvB12E/3Y/+nmIsGeTg5okPsK1XEtUUD/DdkHbVqUbJucMpHKeHF8Px55Qca551pQCs/g+VjNUt6KA==
|
||||
"@intlify/unplugin-vue-i18n@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/unplugin-vue-i18n/-/unplugin-vue-i18n-2.0.0.tgz#5b087e17b4eb4381d0a111cd89df4037880e932f"
|
||||
integrity sha512-1oKvm92L9l2od2H9wKx2ZvR4tzn7gUtd7bPLI7AWUmm7U9H1iEypndt5d985ypxGsEs0gToDaKTrytbBIJwwSg==
|
||||
dependencies:
|
||||
"@intlify/bundle-utils" "^7.4.0"
|
||||
"@intlify/shared" "^9.4.0"
|
||||
@ -690,10 +690,10 @@
|
||||
"@typescript-eslint/parser" "^6.7.0"
|
||||
vue-eslint-parser "^9.3.1"
|
||||
|
||||
"@vue/language-core@1.8.25":
|
||||
version "1.8.25"
|
||||
resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-1.8.25.tgz#b44b4e3c244ba9b1b79cccf9eb7b046535a4676f"
|
||||
integrity sha512-NJk/5DnAZlpvXX8BdWmHI45bWGLViUaS3R/RMrmFSvFMSbJKuEODpM4kR0F0Ofv5SFzCWuNiMhxameWpVdQsnA==
|
||||
"@vue/language-core@1.8.26":
|
||||
version "1.8.26"
|
||||
resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-1.8.26.tgz#7edb6b51a6ed57b618928500c3cbda9757a9f5f0"
|
||||
integrity sha512-9cmza/Y2YTiOnKZ0Mi9zsNn7Irw+aKirP+5LLWVSNaL3fjKJjW1cD3HGBckasY2RuVh4YycvdA9/Q6EBpVd/7Q==
|
||||
dependencies:
|
||||
"@volar/language-core" "~1.11.1"
|
||||
"@volar/source-map" "~1.11.1"
|
||||
@ -2552,10 +2552,10 @@ vite-plugin-compression@^0.5.1:
|
||||
debug "^4.3.3"
|
||||
fs-extra "^10.0.0"
|
||||
|
||||
vite-plugin-css-injected-by-js@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.3.0.tgz#c19480a9e42a95c5bced976a9dde1446f9bd91ff"
|
||||
integrity sha512-xG+jyHNCmUqi/TXp6q88wTJGeAOrNLSyUUTp4qEQ9QZLGcHWQQsCsSSKa59rPMQr8sOzfzmWDd8enGqfH/dBew==
|
||||
vite-plugin-css-injected-by-js@^3.3.1:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.3.1.tgz#26b41f108c5554ee728359bdec01c68c93a48547"
|
||||
integrity sha512-PjM/X45DR3/V1K1fTRs8HtZHEQ55kIfdrn+dzaqNBFrOYO073SeSNCxp4j7gSYhV9NffVHaEnOL4myoko0ePAg==
|
||||
|
||||
vite@^5.0.10:
|
||||
version "5.0.10"
|
||||
@ -2605,13 +2605,13 @@ vue-template-compiler@^2.7.14:
|
||||
de-indent "^1.0.2"
|
||||
he "^1.2.0"
|
||||
|
||||
vue-tsc@^1.8.25:
|
||||
version "1.8.25"
|
||||
resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-1.8.25.tgz#90cd03e71d28c5c4a8068167b232eb97cc96b77f"
|
||||
integrity sha512-lHsRhDc/Y7LINvYhZ3pv4elflFADoEOo67vfClAfF2heVHpHmVquLSjojgCSIwzA4F0Pc4vowT/psXCYcfk+iQ==
|
||||
vue-tsc@^1.8.26:
|
||||
version "1.8.26"
|
||||
resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-1.8.26.tgz#f66abd1dab4e4593590b2b7d4ede0a696882feec"
|
||||
integrity sha512-jMEJ4aqU/l1hdgmeExH5h1TFoN+hbho0A2ZAhHy53/947DGm7Qj/bpB85VpECOCwV00h7JYNVnvoD2ceOorB4Q==
|
||||
dependencies:
|
||||
"@volar/typescript" "~1.11.1"
|
||||
"@vue/language-core" "1.8.25"
|
||||
"@vue/language-core" "1.8.26"
|
||||
semver "^7.5.4"
|
||||
|
||||
vue@^3.3.13:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user