From 2e33f5cd51ca201abea1753d7aa1322371186fdd Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Wed, 15 Mar 2023 20:20:14 +0100 Subject: [PATCH] Display: Implement rotation setting and removed icons --- include/Configuration.h | 2 +- include/Display_Graphic.h | 11 +- include/defaults.h | 2 +- src/Configuration.cpp | 4 +- src/Display_Graphic.cpp | 171 +++++++++++++-------------- src/WebApi_device.cpp | 8 +- src/main.cpp | 5 +- webapp/src/locales/de.json | 6 +- webapp/src/locales/en.json | 6 +- webapp/src/locales/fr.json | 6 +- webapp/src/types/DeviceConfig.ts | 2 +- webapp/src/views/DeviceAdminView.vue | 20 +++- 12 files changed, 136 insertions(+), 107 deletions(-) diff --git a/include/Configuration.h b/include/Configuration.h index 8b9e75a..2bdc950 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -102,7 +102,7 @@ struct CONFIG_T { bool Display_PowerSafe; bool Display_ScreenSaver; - bool Display_ShowLogo; + uint8_t Display_Rotation; uint8_t Display_Contrast; }; diff --git a/include/Display_Graphic.h b/include/Display_Graphic.h index 13f6c62..18c1c3a 100644 --- a/include/Display_Graphic.h +++ b/include/Display_Graphic.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #pragma once +#include "defaults.h" #include enum DisplayType_t { @@ -17,25 +18,29 @@ public: void init(DisplayType_t type, uint8_t data, uint8_t clk, uint8_t cs, uint8_t reset); void loop(); + void setContrast(uint8_t contrast); + void setOrientation(uint8_t rotation = DISPLAY_ROTATION); + void setStartupDisplay(); bool enablePowerSafe = true; bool enableScreensaver = true; - bool showLogo = true; - uint8_t contrast = 60; private: void printText(const char* text, uint8_t line); + void calcLineHeights(); + void setFont(uint8_t line); U8G2* _display; DisplayType_t _display_type = DisplayType_t::None; uint8_t _mExtra; - uint16_t _dispY = 0; uint16_t _period = 1000; uint16_t _interval = 60000; // interval at which to power save (milliseconds) uint32_t _lastDisplayUpdate = 0; uint32_t _previousMillis = 0; char _fmtText[32]; + bool _isLarge = false; + uint8_t _lineOffsets[5]; }; extern DisplayGraphicClass Display; \ No newline at end of file diff --git a/include/defaults.h b/include/defaults.h index 2a86d47..a2ba316 100644 --- a/include/defaults.h +++ b/include/defaults.h @@ -85,5 +85,5 @@ #define DISPLAY_POWERSAFE true #define DISPLAY_SCREENSAVER true -#define DISPLAY_SHOWLOGO true +#define DISPLAY_ROTATION 2 #define DISPLAY_CONTRAST 60 \ No newline at end of file diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 5568d34..6a0cbd5 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -88,7 +88,7 @@ bool ConfigurationClass::write() JsonObject display = device.createNestedObject("display"); display["powersafe"] = config.Display_PowerSafe; display["screensaver"] = config.Display_ScreenSaver; - display["showlogo"] = config.Display_ShowLogo; + display["rotation"] = config.Display_Rotation; display["contrast"] = config.Display_Contrast; JsonArray inverters = doc.createNestedArray("inverters"); @@ -225,7 +225,7 @@ bool ConfigurationClass::read() JsonObject display = device["display"]; config.Display_PowerSafe = display["powersafe"] | DISPLAY_POWERSAFE; config.Display_ScreenSaver = display["screensaver"] | DISPLAY_SCREENSAVER; - config.Display_ShowLogo = display["showlogo"] | DISPLAY_SHOWLOGO; + config.Display_Rotation = display["rotation"] | DISPLAY_ROTATION; config.Display_Contrast = display["contrast"] | DISPLAY_CONTRAST; JsonArray inverters = doc["inverters"]; diff --git a/src/Display_Graphic.cpp b/src/Display_Graphic.cpp index 23c826e..eac532c 100644 --- a/src/Display_Graphic.cpp +++ b/src/Display_Graphic.cpp @@ -5,31 +5,6 @@ #include #include -static uint8_t bmp_logo[] PROGMEM = { - B00000000, B00000000, // ................ - B11101100, B00110111, // ..##.######.##.. - B11101100, B00110111, // ..##.######.##.. - B11100000, B00000111, // .....######..... - B11010000, B00001011, // ....#.####.#.... - B10011000, B00011001, // ...##..##..##... - B10000000, B00000001, // .......##....... - B00000000, B00000000, // ................ - B01111000, B00011110, // ...####..####... - B11111100, B00111111, // ..############.. - B01111100, B00111110, // ..#####..#####.. - B00000000, B00000000, // ................ - B11111100, B00111111, // ..############.. - B11111110, B01111111, // .##############. - B01111110, B01111110, // .######..######. - B00000000, B00000000 // ................ -}; - -static uint8_t bmp_arrow[] PROGMEM = { - B00000000, B00011100, B00011100, B00001110, B00001110, B11111110, B01111111, - B01110000, B01110000, B00110000, B00111000, B00011000, B01111111, B00111111, - B00011110, B00001110, B00000110, B00000000, B00000000, B00000000, B00000000 -}; - std::map> display_types = { { DisplayType_t::PCD8544, [](uint8_t reset, uint8_t clock, uint8_t data, uint8_t cs) { return new U8G2_PCD8544_84X48_F_4W_HW_SPI(U8G2_R0, cs, data, reset); } }, { DisplayType_t::SSD1306, [](uint8_t reset, uint8_t clock, uint8_t data, uint8_t cs) { return new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(U8G2_R0, reset, clock, data); } }, @@ -52,56 +27,83 @@ void DisplayGraphicClass::init(DisplayType_t type, uint8_t data, uint8_t clk, ui auto constructor = display_types[_display_type]; _display = constructor(reset, clk, data, cs); _display->begin(); + setContrast(DISPLAY_CONTRAST); + } +} + +void DisplayGraphicClass::calcLineHeights() +{ + uint8_t yOff = 0; + for (uint8_t i = 0; i < 4; i++) { + setFont(i); + yOff += (_display->getMaxCharHeight()); + _lineOffsets[i] = yOff; + } +} + +void DisplayGraphicClass::setFont(uint8_t line) +{ + switch (line) { + case 0: + _display->setFont((_isLarge) ? u8g2_font_ncenB14_tr : u8g2_font_logisoso16_tr); + break; + case 3: + _display->setFont(u8g2_font_5x8_tr); + break; + default: + _display->setFont((_isLarge) ? u8g2_font_ncenB10_tr : u8g2_font_5x8_tr); + break; } } void DisplayGraphicClass::printText(const char* text, uint8_t line) { - // get the width and height of the display - uint16_t maxWidth = _display->getWidth(); - uint16_t maxHeight = _display->getHeight(); - - // pxMovement +x (0 - 6 px) - uint8_t ex = enableScreensaver ? (_mExtra % 7) : 0; - - // set the font size based on the display size - switch (line) { - case 1: - if (maxWidth > 120 && maxHeight > 60) { - _display->setFont(u8g2_font_ncenB14_tr); // large display - } else { - _display->setFont(u8g2_font_logisoso16_tr); // small display - } - break; - case 4: - if (maxWidth > 120 && maxHeight > 60) { - _display->setFont(u8g2_font_5x8_tr); // large display - } else { - _display->setFont(u8g2_font_5x8_tr); // small display - } - break; - default: - if (maxWidth > 120 && maxHeight > 60) { - _display->setFont(u8g2_font_ncenB10_tr); // large display - } else { - _display->setFont(u8g2_font_5x8_tr); // small display - } - break; - } - - // get the font height, to calculate the textheight - _dispY += (_display->getMaxCharHeight()) + 1; - - // calculate the starting position of the text - uint16_t dispX; - if (line == 1) { - dispX = 20 + ex; + uint8_t dispX; + if (!_isLarge) { + dispX = (line == 0) ? 5 : 0; } else { - dispX = 5 + ex; + dispX = (line == 0) ? 20 : 5; + } + setFont(line); + + dispX += enableScreensaver ? (_mExtra % 7) : 0; + _display->drawStr(dispX, _lineOffsets[line], text); +} + +void DisplayGraphicClass::setOrientation(uint8_t rotation) +{ + if (_display_type == DisplayType_t::None) { + return; } - // draw the Text, on the calculated pos - _display->drawStr(dispX, _dispY, text); + switch (rotation) { + case 0: + _display->setDisplayRotation(U8G2_R0); + break; + case 1: + _display->setDisplayRotation(U8G2_R1); + break; + case 2: + _display->setDisplayRotation(U8G2_R2); + break; + case 3: + _display->setDisplayRotation(U8G2_R3); + break; + } + + _isLarge = (_display->getWidth() > 100); + calcLineHeights(); +} + +void DisplayGraphicClass::setStartupDisplay() +{ + if (_display_type == DisplayType_t::None) { + return; + } + + _display->clearBuffer(); + printText("OpenDTU!", 0); + _display->sendBuffer(); } void DisplayGraphicClass::loop() @@ -136,20 +138,6 @@ void DisplayGraphicClass::loop() _display->clearBuffer(); - // set Contrast of the Display to raise the lifetime - _display->setContrast(contrast); - - //=====> Logo and Lighting ========== - // pxMovement +x (0 - 6 px) - uint8_t ex = enableScreensaver ? (_mExtra % 7) : 0; - if (isprod > 0) { - _display->drawXBMP(5 + ex, 1, 8, 17, bmp_arrow); - if (showLogo) { - _display->drawXBMP(_display->getWidth() - 24 + ex, 2, 16, 16, bmp_logo); - } - } - //<======================= - //=====> Actual Production ========== if ((totalPower > 0) && (isprod > 0)) { _display->setPowerSave(false); @@ -158,14 +146,14 @@ void DisplayGraphicClass::loop() } else { snprintf(_fmtText, sizeof(_fmtText), "%3.0f W", totalPower); } - printText(_fmtText, 1); + printText(_fmtText, 0); _previousMillis = millis(); } //<======================= //=====> Offline =========== else { - printText("offline", 1); + printText("offline", 0); // check if it's time to enter power saving mode if (millis() - _previousMillis >= (_interval * 2)) { _display->setPowerSave(enablePowerSafe); @@ -175,27 +163,34 @@ void DisplayGraphicClass::loop() //=====> Today & Total Production ======= snprintf(_fmtText, sizeof(_fmtText), "today: %4.0f Wh", totalYieldDay); - printText(_fmtText, 2); + printText(_fmtText, 1); snprintf(_fmtText, sizeof(_fmtText), "total: %.1f kWh", totalYieldTotal); - printText(_fmtText, 3); + printText(_fmtText, 2); //<======================= //=====> IP or Date-Time ======== if (!(_mExtra % 10) && NetworkSettings.localIP()) { - printText(NetworkSettings.localIP().toString().c_str(), 4); + printText(NetworkSettings.localIP().toString().c_str(), 3); } else { // Get current time time_t now = time(nullptr); strftime(_fmtText, sizeof(_fmtText), "%a %d.%m.%Y %H:%M", localtime(&now)); - printText(_fmtText, 4); + printText(_fmtText, 3); } _display->sendBuffer(); - _dispY = 0; _mExtra++; _lastDisplayUpdate = millis(); } } +void DisplayGraphicClass::setContrast(uint8_t contrast) +{ + if (_display_type == DisplayType_t::None) { + return; + } + _display->setContrast(contrast * 2.55f); +} + DisplayGraphicClass Display; \ No newline at end of file diff --git a/src/WebApi_device.cpp b/src/WebApi_device.cpp index 44f6824..0585e60 100644 --- a/src/WebApi_device.cpp +++ b/src/WebApi_device.cpp @@ -64,7 +64,7 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request) displayPinObj[F("reset")] = pin.display_reset; JsonObject display = root.createNestedObject("display"); - display[F("show_logo")] = config.Display_ShowLogo; + display[F("rotation")] = config.Display_Rotation; display[F("power_safe")] = config.Display_PowerSafe; display[F("screensaver")] = config.Display_ScreenSaver; display[F("contrast")] = config.Display_Contrast; @@ -133,15 +133,15 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request) bool performRestart = root[F("curPin")][F("name")].as() != config.Dev_PinMapping; strlcpy(config.Dev_PinMapping, root[F("curPin")][F("name")].as().c_str(), sizeof(config.Dev_PinMapping)); - config.Display_ShowLogo = root[F("display")][F("show_logo")].as(); + config.Display_Rotation = root[F("display")][F("rotation")].as(); config.Display_PowerSafe = root[F("display")][F("power_safe")].as(); config.Display_ScreenSaver = root[F("display")][F("screensaver")].as(); config.Display_Contrast = root[F("display")][F("contrast")].as(); - Display.showLogo = config.Display_ShowLogo; + Display.setOrientation(config.Display_Rotation); Display.enablePowerSafe = config.Display_PowerSafe; Display.enableScreensaver = config.Display_ScreenSaver; - Display.contrast = config.Display_Contrast; + Display.setContrast(config.Display_Contrast); Configuration.write(); diff --git a/src/main.cpp b/src/main.cpp index 3cdefa3..58e663c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -107,10 +107,11 @@ void setup() pin.display_clk, pin.display_cs, pin.display_reset); - Display.showLogo = config.Display_ShowLogo; + Display.setOrientation(config.Display_Rotation); Display.enablePowerSafe = config.Display_PowerSafe; Display.enableScreensaver = config.Display_ScreenSaver; - Display.contrast = config.Display_Contrast; + Display.setContrast(config.Display_Contrast); + Display.setStartupDisplay(); MessageOutput.println(F("done")); // Check for default DTU serial diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index f78e226..10a9834 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -508,8 +508,12 @@ "PowerSafeHint": "Schaltet das Display aus, wenn kein Wechselrichter Strom erzeugt", "Screensaver": "Screensaver aktivieren:", "ScreensaverHint": "Bewegt die Ausgabe bei jeder Aktualisierung um ein Einbrennen zu verhindern (v. a. für OLED-Displays nützlich)", - "ShowLogo": "Logo anzeigen:", "Contrast": "Kontrast ({contrast}):", + "Rotation": "Rotation:", + "rot0": "Keine Rotation", + "rot90": "90 Grad Drehung", + "rot180": "180 Grad Drehung", + "rot270": "270 Grad Drehung", "Save": "@:dtuadmin.Save" }, "pininfo": { diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index 986abd0..a0a3ff0 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -508,8 +508,12 @@ "PowerSafeHint": "Turn off the display if no inverter is producing.", "Screensaver": "Enable Screensaver:", "ScreensaverHint": "Move the display a little bit on each update to prevent burn-in. (Useful especially for OLED displays)", - "ShowLogo": "Show Logo:", "Contrast": "Contrast ({contrast}):", + "Rotation": "Rotation:", + "rot0": "No rotation", + "rot90": "90 degree rotation", + "rot180": "180 degree rotation", + "rot270": "270 degree rotation", "Save": "@:dtuadmin.Save" }, "pininfo": { diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index 4746202..55a421c 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -508,8 +508,12 @@ "PowerSafeHint": "Eteindre l'écran si aucun onduleur n'est en production.", "Screensaver": "Activer l'écran de veille", "ScreensaverHint": "Déplacez un peu l'écran à chaque mise à jour pour éviter le phénomène de brûlure. (Utile surtout pour les écrans OLED)", - "ShowLogo": "Afficher le logo", "Contrast": "Contraste ({contrast}):", + "Rotation": "Rotation:", + "rot0": "No rotation", + "rot90": "90 degree rotation", + "rot180": "180 degree rotation", + "rot270": "270 degree rotation", "Save": "@:dtuadmin.Save" }, "pininfo": { diff --git a/webapp/src/types/DeviceConfig.ts b/webapp/src/types/DeviceConfig.ts index 99ce70c..8bd87f7 100644 --- a/webapp/src/types/DeviceConfig.ts +++ b/webapp/src/types/DeviceConfig.ts @@ -1,7 +1,7 @@ import type { Device } from "./PinMapping"; export interface Display { - show_logo: boolean; + rotation: number; power_safe: boolean; screensaver: boolean; contrast: number; diff --git a/webapp/src/views/DeviceAdminView.vue b/webapp/src/views/DeviceAdminView.vue index 0eccf5b..b8da577 100644 --- a/webapp/src/views/DeviceAdminView.vue +++ b/webapp/src/views/DeviceAdminView.vue @@ -57,8 +57,18 @@ v-model="deviceConfigList.display.screensaver" type="checkbox" :tooltip="$t('deviceadmin.ScreensaverHint')" /> - +
+ +
+ +
+