forked from tbnobody/OpenDTU
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDisplay_Graphic_Diagram.cpp
136 lines (114 loc) · 5.08 KB
/
Display_Graphic_Diagram.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2023-2024 Thomas Basler and others
*/
#include "Display_Graphic_Diagram.h"
#include "Configuration.h"
#include "Datastore.h"
#include <algorithm>
DisplayGraphicDiagramClass::DisplayGraphicDiagramClass()
: _averageTask(1 * TASK_SECOND, TASK_FOREVER, std::bind(&DisplayGraphicDiagramClass::averageLoop, this))
, _dataPointTask(TASK_IMMEDIATE, TASK_FOREVER, std::bind(&DisplayGraphicDiagramClass::dataPointLoop, this))
{
}
void DisplayGraphicDiagramClass::init(Scheduler& scheduler, U8G2* display)
{
_display = display;
scheduler.addTask(_averageTask);
_averageTask.enable();
scheduler.addTask(_dataPointTask);
updatePeriod();
_dataPointTask.enable();
}
void DisplayGraphicDiagramClass::averageLoop()
{
const float currentWatts = Datastore.getTotalAcPowerEnabled(); // get the current AC production
_iRunningAverage += currentWatts;
_iRunningAverageCnt++;
}
void DisplayGraphicDiagramClass::dataPointLoop()
{
if (_graphValuesCount >= std::size(_graphValues)) {
for (uint8_t i = 0; i < std::size(_graphValues) - 1; i++) {
_graphValues[i] = _graphValues[i + 1];
}
_graphValuesCount = std::size(_graphValues) - 1;
}
if (_iRunningAverageCnt != 0) {
_graphValues[_graphValuesCount++] = _iRunningAverage / _iRunningAverageCnt;
_iRunningAverage = 0;
_iRunningAverageCnt = 0;
}
}
uint32_t DisplayGraphicDiagramClass::getSecondsPerDot()
{
return Configuration.get().Display.Diagram.Duration / _chartWidth;
}
void DisplayGraphicDiagramClass::updatePeriod()
{
// Calculate seconds per datapoint
_dataPointTask.setInterval(Configuration.get().Display.Diagram.Duration * TASK_SECOND / MAX_DATAPOINTS);
}
void DisplayGraphicDiagramClass::redraw(uint8_t screenSaverOffsetX, uint8_t xPos, uint8_t yPos, uint8_t width, uint8_t height, bool isFullscreen)
{
_chartWidth = width;
// screenSaverOffsetX expected to be in range 0..6
const uint8_t graphPosX = xPos + ((screenSaverOffsetX > 3) ? 1 : 0);
const uint8_t graphPosY = yPos + ((screenSaverOffsetX > 3) ? 1 : 0);
const uint8_t horizontal_line_y = graphPosY + height - 1;
const uint8_t arrow_size = 2;
// draw diagram axis
_display->drawVLine(graphPosX, graphPosY, height);
_display->drawHLine(graphPosX, horizontal_line_y, width);
// UP-arrow
_display->drawLine(graphPosX, graphPosY, graphPosX + arrow_size, graphPosY + arrow_size);
_display->drawLine(graphPosX, graphPosY, graphPosX - arrow_size, graphPosY + arrow_size);
// LEFT-arrow
_display->drawLine(graphPosX + width - 1, horizontal_line_y, graphPosX + width - 1 - arrow_size, horizontal_line_y - arrow_size);
_display->drawLine(graphPosX + width - 1, horizontal_line_y, graphPosX + width - 1 - arrow_size, horizontal_line_y + arrow_size);
// draw AC value
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));
}
if (isFullscreen) {
_display->setFont(u8g2_font_5x8_tr);
_display->setFontDirection(3);
_display->drawStr(graphPosX - arrow_size, graphPosY + _display->getStrWidth(fmtText), fmtText);
_display->setFontDirection(0);
} else {
// 4 pixels per char
_display->setFont(u8g2_font_tom_thumb_4x6_mr);
_display->drawStr(graphPosX - arrow_size - _display->getStrWidth(fmtText), graphPosY + 5, fmtText);
}
// draw chart
const float scaleFactorY = maxWatts / static_cast<float>(height);
const float scaleFactorX = static_cast<float>(MAX_DATAPOINTS) / static_cast<float>(_chartWidth);
if (maxWatts > 0 && isFullscreen) {
// draw y axis ticks
const uint16_t yAxisWattPerTick = maxWatts <= 100 ? 10 : maxWatts <= 1000 ? 100
: maxWatts < 5000 ? 500
: 1000;
const uint8_t yAxisTickSizePixel = height / (maxWatts / yAxisWattPerTick);
for (int16_t tickYPos = graphPosY + height; tickYPos > graphPosY - arrow_size; tickYPos -= yAxisTickSizePixel) {
_display->drawPixel(graphPosX - 1, tickYPos);
}
}
uint8_t xAxisTicks = 1;
for (uint8_t i = 1; i < _graphValuesCount; i++) {
// draw one tick per hour to the x-axis
if (i * getSecondsPerDot() > (3600u * xAxisTicks)) {
_display->drawPixel((graphPosX + 1 + i) * scaleFactorX, graphPosY + height);
xAxisTicks++;
}
if (scaleFactorY == 0 || scaleFactorX == 0) {
continue;
}
_display->drawLine(
graphPosX + (i - 1) / scaleFactorX, horizontal_line_y - std::max<int16_t>(0, _graphValues[i - 1] / scaleFactorY - 0.5),
graphPosX + i / scaleFactorX, horizontal_line_y - std::max<int16_t>(0, _graphValues[i] / scaleFactorY - 0.5));
}
}