Display: Implement rotation setting and removed icons
This commit is contained in:
parent
c0b5049a74
commit
2e33f5cd51
@ -102,7 +102,7 @@ struct CONFIG_T {
|
||||
|
||||
bool Display_PowerSafe;
|
||||
bool Display_ScreenSaver;
|
||||
bool Display_ShowLogo;
|
||||
uint8_t Display_Rotation;
|
||||
uint8_t Display_Contrast;
|
||||
};
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma once
|
||||
|
||||
#include "defaults.h"
|
||||
#include <U8g2lib.h>
|
||||
|
||||
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;
|
||||
@ -85,5 +85,5 @@
|
||||
|
||||
#define DISPLAY_POWERSAFE true
|
||||
#define DISPLAY_SCREENSAVER true
|
||||
#define DISPLAY_SHOWLOGO true
|
||||
#define DISPLAY_ROTATION 2
|
||||
#define DISPLAY_CONTRAST 60
|
||||
@ -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"];
|
||||
|
||||
@ -5,31 +5,6 @@
|
||||
#include <map>
|
||||
#include <time.h>
|
||||
|
||||
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<DisplayType_t, std::function<U8G2*(uint8_t, uint8_t, uint8_t, uint8_t)>> 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();
|
||||
uint8_t dispX;
|
||||
if (!_isLarge) {
|
||||
dispX = (line == 0) ? 5 : 0;
|
||||
} else {
|
||||
dispX = (line == 0) ? 20 : 5;
|
||||
}
|
||||
setFont(line);
|
||||
|
||||
// pxMovement +x (0 - 6 px)
|
||||
uint8_t ex = enableScreensaver ? (_mExtra % 7) : 0;
|
||||
dispX += enableScreensaver ? (_mExtra % 7) : 0;
|
||||
_display->drawStr(dispX, _lineOffsets[line], text);
|
||||
}
|
||||
|
||||
// set the font size based on the display size
|
||||
switch (line) {
|
||||
void DisplayGraphicClass::setOrientation(uint8_t rotation)
|
||||
{
|
||||
if (_display_type == DisplayType_t::None) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (rotation) {
|
||||
case 0:
|
||||
_display->setDisplayRotation(U8G2_R0);
|
||||
break;
|
||||
case 1:
|
||||
if (maxWidth > 120 && maxHeight > 60) {
|
||||
_display->setFont(u8g2_font_ncenB14_tr); // large display
|
||||
} else {
|
||||
_display->setFont(u8g2_font_logisoso16_tr); // small display
|
||||
}
|
||||
_display->setDisplayRotation(U8G2_R1);
|
||||
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
|
||||
}
|
||||
case 2:
|
||||
_display->setDisplayRotation(U8G2_R2);
|
||||
break;
|
||||
default:
|
||||
if (maxWidth > 120 && maxHeight > 60) {
|
||||
_display->setFont(u8g2_font_ncenB10_tr); // large display
|
||||
} else {
|
||||
_display->setFont(u8g2_font_5x8_tr); // small display
|
||||
}
|
||||
case 3:
|
||||
_display->setDisplayRotation(U8G2_R3);
|
||||
break;
|
||||
}
|
||||
|
||||
// get the font height, to calculate the textheight
|
||||
_dispY += (_display->getMaxCharHeight()) + 1;
|
||||
_isLarge = (_display->getWidth() > 100);
|
||||
calcLineHeights();
|
||||
}
|
||||
|
||||
// calculate the starting position of the text
|
||||
uint16_t dispX;
|
||||
if (line == 1) {
|
||||
dispX = 20 + ex;
|
||||
} else {
|
||||
dispX = 5 + ex;
|
||||
void DisplayGraphicClass::setStartupDisplay()
|
||||
{
|
||||
if (_display_type == DisplayType_t::None) {
|
||||
return;
|
||||
}
|
||||
|
||||
// draw the Text, on the calculated pos
|
||||
_display->drawStr(dispX, _dispY, text);
|
||||
_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;
|
||||
@ -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<String>() != config.Dev_PinMapping;
|
||||
|
||||
strlcpy(config.Dev_PinMapping, root[F("curPin")][F("name")].as<String>().c_str(), sizeof(config.Dev_PinMapping));
|
||||
config.Display_ShowLogo = root[F("display")][F("show_logo")].as<bool>();
|
||||
config.Display_Rotation = root[F("display")][F("rotation")].as<uint8_t>();
|
||||
config.Display_PowerSafe = root[F("display")][F("power_safe")].as<bool>();
|
||||
config.Display_ScreenSaver = root[F("display")][F("screensaver")].as<bool>();
|
||||
config.Display_Contrast = root[F("display")][F("contrast")].as<uint8_t>();
|
||||
|
||||
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();
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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": {
|
||||
|
||||
@ -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": {
|
||||
|
||||
@ -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": {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type { Device } from "./PinMapping";
|
||||
|
||||
export interface Display {
|
||||
show_logo: boolean;
|
||||
rotation: number;
|
||||
power_safe: boolean;
|
||||
screensaver: boolean;
|
||||
contrast: number;
|
||||
|
||||
@ -57,8 +57,18 @@
|
||||
v-model="deviceConfigList.display.screensaver" type="checkbox"
|
||||
:tooltip="$t('deviceadmin.ScreensaverHint')" />
|
||||
|
||||
<InputElement :label="$t('deviceadmin.ShowLogo')"
|
||||
v-model="deviceConfigList.display.show_logo" type="checkbox" />
|
||||
<div class="row mb-3">
|
||||
<label class="col-sm-2 col-form-label">
|
||||
{{ $t('deviceadmin.Rotation') }}
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="form-select" v-model="deviceConfigList.display.rotation">
|
||||
<option v-for="rotation in displayRotationList" :key="rotation.key" :value="rotation.key">
|
||||
{{ rotation.value }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label for="inputDisplayContrast" class="col-sm-2 col-form-label">{{
|
||||
@ -108,6 +118,12 @@ export default defineComponent({
|
||||
alertMessage: "",
|
||||
alertType: "info",
|
||||
showAlert: false,
|
||||
displayRotationList: [
|
||||
{ key: 0, value: this.$t('deviceadmin.rot0') },
|
||||
{ key: 1, value: this.$t('deviceadmin.rot90') },
|
||||
{ key: 2, value: this.$t('deviceadmin.rot180') },
|
||||
{ key: 3, value: this.$t('deviceadmin.rot270') },
|
||||
],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user