mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-28 04:07:47 +00:00
[P104] Add Bar-graph support and bar/setbar commands
This commit is contained in:
@@ -49,8 +49,19 @@
|
||||
// brightness,<zone>,<level> : Set the Brightness for the zone, range from 0 (off) to 15 (very bright)
|
||||
// repeat,<zone>,<delay_sec> : Set the Repeat (sec) for the zone, after this delay the text & animation will be repeated.
|
||||
// -1 = off, range 0..86400 seconds (24h)
|
||||
// bar,<zone>,<graph-string> : Set the graph-string for a Bargraph zone, format: value,max,min,direction,barType|...
|
||||
// value: numeric value of type double
|
||||
// max: value for a full bar display, default 100 (percent)
|
||||
// min: value for minimal bar display, default 0
|
||||
// direction: 0 (default): right to left, 1: left to right
|
||||
// barType: 0: solid, width: 8/number of graphStrings
|
||||
// 1: solid, width: 1 on, 1 off
|
||||
// Up to 8 graphStrings can be provided, width is determined by the number of graphStrings
|
||||
//
|
||||
// History:
|
||||
// 2021-06-24 tonhuisman: Add min/max range with negative minimal value support and zero-point indication if possible
|
||||
// 2021-06-23 tonhuisman: Add Bar-graph option and bar command (initial feature, options to implement) guarded with P104_USE_BAR_GRAPH
|
||||
// 2021-06-22 tonhuisman: Add Bar-graph initial code-infrastructure
|
||||
// 2021-06-21 tonhuisman: Add options for 'formatting' time & date, will be disabled on memory-tight configs guarded by
|
||||
// P104_USE_DATETIME_OPTIONS
|
||||
// Introduced guard P104_ADD_SETTINGS_NOTES to disable some addFormNotes() to further reduce code size
|
||||
|
||||
@@ -49,6 +49,9 @@ bool P104_data_struct::begin() {
|
||||
if ((P != nullptr) && (cs_pin > -1)) {
|
||||
addLog(LOG_LEVEL_INFO, F("dotmatrix: P->begin() called"));
|
||||
P->begin(expectedZones);
|
||||
#ifdef P104_USE_BAR_GRAPH
|
||||
pM = P->getGraphicObject();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -269,6 +272,10 @@ void P104_data_struct::configureZones() {
|
||||
if (it->zone <= expectedZones) {
|
||||
zoneOffset += it->offset;
|
||||
P->setZone(currentZone, zoneOffset, zoneOffset + it->size - 1);
|
||||
# ifdef P104_USE_BAR_GRAPH
|
||||
it->_startModule = zoneOffset;
|
||||
P->getDisplayExtent(currentZone, it->_lower, it->_upper);
|
||||
# endif // ifdef P104_USE_BAR_GRAPH
|
||||
zoneOffset += it->size;
|
||||
|
||||
switch (it->font) {
|
||||
@@ -400,6 +407,187 @@ void P104_data_struct::displayOneZoneText(uint8_t zone,
|
||||
static_cast<textEffect_t>(zstruct.animationOut));
|
||||
}
|
||||
|
||||
# ifdef P104_USE_BAR_GRAPH
|
||||
|
||||
void P104_data_struct::modulesOnOff(uint8_t start, uint8_t end, MD_MAX72XX::controlValue_t on_off) {
|
||||
for (uint8_t m = start; m <= end; m++) {
|
||||
pM->control(m, MD_MAX72XX::UPDATE, on_off);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Process a graph-string to display in a zone, format:
|
||||
* value,100%-range,direction,bartype|...
|
||||
*******************************************************************/
|
||||
void P104_data_struct::displayBarGraph(uint8_t zone,
|
||||
const P104_zone_struct& zstruct,
|
||||
const String&graph) {
|
||||
// TODO
|
||||
if (graph.isEmpty()) { return; }
|
||||
sZoneInitial[zone] = String(graph); // Keep the original string for future use
|
||||
|
||||
# define NOT_A_COMMA 0x02 // Something else than a comma, or the parseString function will get confused
|
||||
String parsedGraph = String(graph);
|
||||
parseTemplate(parsedGraph);
|
||||
parsedGraph.replace(',', NOT_A_COMMA);
|
||||
|
||||
std::vector<P104_bargraph_struct> barGraphs;
|
||||
uint8_t currentBar = 0;
|
||||
bool loop = true;
|
||||
// Parse the graph-string
|
||||
while (loop && currentBar < 8) { // Maximum 8 valuesets possible
|
||||
String graphpart = parseString(parsedGraph, currentBar + 1, '|');
|
||||
graphpart.trim();
|
||||
graphpart.replace(NOT_A_COMMA, ',');
|
||||
if (graphpart.isEmpty()) {
|
||||
loop = false;
|
||||
} else {
|
||||
barGraphs.push_back(P104_bargraph_struct(currentBar));
|
||||
}
|
||||
if (loop && validDoubleFromString(parseString(graphpart, 1), barGraphs[currentBar].value)) { // value
|
||||
String datapart = parseString(graphpart, 2); // max (default: 100.0)
|
||||
if (datapart.isEmpty()) {
|
||||
barGraphs[currentBar].max = 100.0;
|
||||
} else {
|
||||
validDoubleFromString(datapart, barGraphs[currentBar].max);
|
||||
}
|
||||
datapart = parseString(graphpart, 3); // min (default: 0.0)
|
||||
if (datapart.isEmpty()) {
|
||||
barGraphs[currentBar].min = 0.0;
|
||||
} else {
|
||||
validDoubleFromString(datapart, barGraphs[currentBar].min);
|
||||
}
|
||||
datapart = parseString(graphpart, 4); // direction
|
||||
if (datapart.isEmpty()) {
|
||||
barGraphs[currentBar].direction = 0;
|
||||
} else {
|
||||
int value = 0;
|
||||
validIntFromString(datapart, value);
|
||||
barGraphs[currentBar].direction = value;
|
||||
}
|
||||
datapart = parseString(graphpart, 5); // barType
|
||||
if (datapart.isEmpty()) {
|
||||
barGraphs[currentBar].barType = 0;
|
||||
} else {
|
||||
int value = 0;
|
||||
validIntFromString(datapart, value);
|
||||
barGraphs[currentBar].barType = value;
|
||||
}
|
||||
if (definitelyGreaterThan(barGraphs[currentBar].min, barGraphs[currentBar].max)) {
|
||||
std::swap(barGraphs[currentBar].min, barGraphs[currentBar].max);
|
||||
}
|
||||
}
|
||||
#ifdef P104_DEBUG // Temporary logging
|
||||
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
|
||||
String log;
|
||||
log.reserve(70);
|
||||
log = F("P104: Bar-graph: ");
|
||||
if (loop) {
|
||||
log += currentBar;
|
||||
log += F(" in: ");
|
||||
log += graphpart;
|
||||
log += F(" value: ");
|
||||
log += barGraphs[currentBar].value;
|
||||
log += F(" max: ");
|
||||
log += barGraphs[currentBar].max;
|
||||
log += F(" min: ");
|
||||
log += barGraphs[currentBar].min;
|
||||
log += F(" dir: ");
|
||||
log += barGraphs[currentBar].direction;
|
||||
log += F(" typ: ");
|
||||
log += barGraphs[currentBar].barType;
|
||||
} else {
|
||||
log += F(" bsize: ");
|
||||
log += barGraphs.size();
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
#endif
|
||||
currentBar++; // next
|
||||
}
|
||||
# undef NOT_A_COMMA
|
||||
if (barGraphs.size() > 0) {
|
||||
uint8_t barWidth = 8 / barGraphs.size(); // Divide the 8 pixel width per number of bars to show
|
||||
uint8_t pixTop, pixBottom;
|
||||
int16_t zeroPoint;
|
||||
#ifdef P104_DEBUG
|
||||
String log;
|
||||
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
|
||||
log.reserve(64);
|
||||
log = F("P104: bar Width: ");
|
||||
log += barWidth;
|
||||
log += F(" low: ");
|
||||
log += zstruct._lower;
|
||||
log += F(" high: ");
|
||||
log += zstruct._upper;
|
||||
}
|
||||
#endif
|
||||
modulesOnOff(zstruct._startModule, zstruct._startModule + zstruct.size - 1, MD_MAX72XX::MD_OFF); // Stop updates on modules
|
||||
uint8_t row = 0;
|
||||
if (barGraphs.size() == 3 || barGraphs.size() == 5) { // Center within the rows a bit
|
||||
for (;row < (barGraphs.size() == 3 ? 1 : 2); row++) {
|
||||
for (uint8_t col = zstruct._lower; col < zstruct._upper; col++) {
|
||||
pM->setPoint(row, col, false); // all off
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto it = barGraphs.begin(); it != barGraphs.end(); ++it) {
|
||||
if (essentiallyEqual(it->min, 0.0)) {
|
||||
pixTop = zstruct._lower + ((zstruct._upper - zstruct._lower) / it->max) * it->value;
|
||||
pixBottom = 0;
|
||||
zeroPoint = 0;
|
||||
} else {
|
||||
if (definitelyLessThan(it->min, 0.0) && definitelyGreaterThan(it->max, 0.0)) { // Zero-point is used
|
||||
zeroPoint = (it->min * -1) / ((it->max - it->min) / (1.0 * (zstruct._upper - zstruct._lower)));
|
||||
} else {
|
||||
zeroPoint = 0;
|
||||
}
|
||||
pixTop = zstruct._lower + zeroPoint + ((zstruct._upper - zstruct._lower) / (it->max - it->min)) * it->value;
|
||||
pixBottom = zstruct._lower + zeroPoint;
|
||||
if (definitelyLessThan(it->value, 0.0)) {
|
||||
std::swap(pixTop, pixBottom); }
|
||||
}
|
||||
#ifdef P104_DEBUG
|
||||
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
|
||||
log += F(" B: ");
|
||||
log += pixBottom;
|
||||
log += F(" T: ");
|
||||
log += pixTop;
|
||||
log += F(" Z: ");
|
||||
log += zeroPoint;
|
||||
}
|
||||
#endif
|
||||
bool on_off;
|
||||
for (uint8_t r = 0; r < barWidth; r++) {
|
||||
for (uint8_t col = zstruct._lower; col < zstruct._upper; col++) {
|
||||
if (zeroPoint == 0) {
|
||||
on_off = col <= pixTop;
|
||||
} else {
|
||||
on_off = (col >= pixBottom && col <= pixTop); // valid area
|
||||
if (barWidth > 2 && (r == 0 || r == barWidth - 1) && col == zstruct._lower + zeroPoint) {
|
||||
on_off = false; // when bar wider than 2, turn off zeropoint top and bottom led
|
||||
}
|
||||
}
|
||||
pM->setPoint(row + r, col, on_off);
|
||||
}
|
||||
}
|
||||
row += barWidth; // Next set of rows
|
||||
}
|
||||
for (; row < 8; row++) { // Clear unused rows
|
||||
for (uint8_t col = zstruct._lower; col < zstruct._upper; col++) {
|
||||
pM->setPoint(row, col, false); // all off
|
||||
}
|
||||
}
|
||||
#ifdef P104_DEBUG
|
||||
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
#endif
|
||||
modulesOnOff(zstruct._startModule, zstruct._startModule + zstruct.size - 1, MD_MAX72XX::MD_ON); // Continue updates on modules
|
||||
}
|
||||
}
|
||||
# endif // ifdef P104_USE_BAR_GRAPH
|
||||
|
||||
/**************************************************
|
||||
* Check if an animatio is available in the current build
|
||||
*************************************************/
|
||||
@@ -678,6 +866,19 @@ bool P104_data_struct::handlePluginWrite(taskIndex_t taskIndex,
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef P104_USE_BAR_GRAPH
|
||||
if ((sub.equals(F("bar")) || // subcommand: [set]bar,<zone>,<graph-string> (only allowed for zones with Bargraph content)
|
||||
sub.equals(F("setbar"))) &&
|
||||
(it->content == P104_CONTENT_BAR_GRAPH)) { // no length check, so longer than the UI allows is made possible
|
||||
if (sub.equals(F("setbar"))) { // subcommand: setbar,<zone>,<graph-string> (stores the graph-string in the settings, is not saved)
|
||||
it->text = string4;
|
||||
}
|
||||
displayBarGraph(zoneIndex - 1, *it, string4);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -919,6 +1120,15 @@ bool P104_data_struct::handlePluginOncePerSecond(struct EventStruct *event) {
|
||||
it->_lastChecked = m;
|
||||
break;
|
||||
}
|
||||
# ifdef P104_USE_BAR_GRAPH
|
||||
case P104_CONTENT_BAR_GRAPH:
|
||||
{
|
||||
if (!it->text.isEmpty()) {
|
||||
displayBarGraph(it->zone - 1, *it, it->text);
|
||||
}
|
||||
break;
|
||||
}
|
||||
# endif // ifdef P104_USE_BAR_GRAPH
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -967,8 +1177,15 @@ void P104_data_struct::checkRepeatTimer(uint8_t z) {
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
# endif // ifdef P104_DEBUG
|
||||
displayOneZoneText(it->zone - 1, *it, sZoneInitial[it->zone - 1]); // Re-send last displayed text
|
||||
P->displayReset(it->zone - 1);
|
||||
if (it->content == P104_CONTENT_TEXT) {
|
||||
displayOneZoneText(it->zone - 1, *it, sZoneInitial[it->zone - 1]); // Re-send last displayed text
|
||||
P->displayReset(it->zone - 1);
|
||||
}
|
||||
#ifdef P104_USE_BAR_GRAPH
|
||||
if (it->content == P104_CONTENT_BAR_GRAPH) {
|
||||
displayBarGraph(it->zone - 1, *it, sZoneInitial[it->zone - 1]); // Re-send last displayed text
|
||||
}
|
||||
#endif
|
||||
it->_repeatTimer = millis();
|
||||
}
|
||||
}
|
||||
@@ -1538,6 +1755,9 @@ bool P104_data_struct::webform_load(struct EventStruct *event) {
|
||||
F("Date (4 mod.)"),
|
||||
F("Date yr (6/7 mod.)"),
|
||||
F("Date/time (9/13 mod.)")
|
||||
#ifdef P104_USE_BAR_GRAPH
|
||||
, F("Bar graph")
|
||||
#endif
|
||||
};
|
||||
int contentOptions[] {
|
||||
P104_CONTENT_TEXT,
|
||||
@@ -1546,6 +1766,9 @@ bool P104_data_struct::webform_load(struct EventStruct *event) {
|
||||
P104_CONTENT_DATE4,
|
||||
P104_CONTENT_DATE6,
|
||||
P104_CONTENT_DATE_TIME
|
||||
#ifdef P104_USE_BAR_GRAPH
|
||||
, P104_CONTENT_BAR_GRAPH
|
||||
#endif
|
||||
};
|
||||
|
||||
delay(0);
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
# define P104_USE_KATAKANA_FONT // Enables the use of a Katakana font (see usage in MD_Parola examples)
|
||||
# define P104_USE_COMMANDS // Enables the use of all commands, not just clear, txt and settxt
|
||||
# define P104_USE_DATETIME_OPTIONS // Enables extra date/time options
|
||||
# define P104_USE_BAR_GRAPH // Enables the use of Bar-graph feature
|
||||
|
||||
# define P104_ADD_SETTINGS_NOTES // Adds some notes on the Settings page
|
||||
|
||||
# if defined(PLUGIN_DISPLAY_COLLECTION) && defined(ESP8266) // To make it fit in the ESP8266 display build
|
||||
@@ -186,7 +188,12 @@
|
||||
# define P104_CONTENT_DATE4 3
|
||||
# define P104_CONTENT_DATE6 4
|
||||
# define P104_CONTENT_DATE_TIME 5
|
||||
# define P104_CONTENT_count 6 // The number of content type options
|
||||
# define P104_CONTENT_BAR_GRAPH 6
|
||||
# ifdef P104_USE_BAR_GRAPH
|
||||
# define P104_CONTENT_count 7 // The number of content type options
|
||||
# else // ifdef P104_USE_BAR_GRAPH
|
||||
# define P104_CONTENT_count 6 // The number of content type options
|
||||
# endif // ifdef P104_USE_BAR_GRAPH
|
||||
|
||||
# define P104_SPECIAL_EFFECT_NONE 0
|
||||
# define P104_SPECIAL_EFFECT_UP_DOWN 1
|
||||
@@ -282,8 +289,25 @@ struct P104_zone_struct {
|
||||
int32_t repeatDelay;
|
||||
uint32_t _repeatTimer;
|
||||
int8_t _lastChecked = -1;
|
||||
# ifdef P104_USE_BAR_GRAPH
|
||||
uint8_t _startModule; // starting module, end module is _startModule + size - 1
|
||||
uint16_t _lower, _upper; // lower and upper pixel numbers
|
||||
# endif // ifdef P104_USE_BAR_GRAPH
|
||||
};
|
||||
|
||||
# ifdef P104_USE_BAR_GRAPH
|
||||
struct P104_bargraph_struct {
|
||||
P104_bargraph_struct(uint8_t _graph) : graph(_graph) {}
|
||||
|
||||
uint8_t graph;
|
||||
double value;
|
||||
double max;
|
||||
double min;
|
||||
uint8_t barType;
|
||||
uint8_t direction;
|
||||
};
|
||||
# endif // ifdef P104_USE_BAR_GRAPH
|
||||
|
||||
struct tP104_StoredSettings {
|
||||
uint16_t bufferSize = 0u;
|
||||
char buffer[P104_SETTINGS_BUFFER]; // Max. acceptable value would be ~1020
|
||||
@@ -314,8 +338,19 @@ struct P104_data_struct : public PluginTaskData_base {
|
||||
const String& string);
|
||||
bool handlePluginOncePerSecond(struct EventStruct *event);
|
||||
void checkRepeatTimer(uint8_t z);
|
||||
# ifdef P104_USE_BAR_GRAPH
|
||||
void displayBarGraph(uint8_t zone,
|
||||
const P104_zone_struct& zstruct,
|
||||
const String & graph);
|
||||
# endif // ifdef P104_USE_BAR_GRAPH
|
||||
|
||||
MD_Parola *P = nullptr;
|
||||
# ifdef P104_USE_BAR_GRAPH
|
||||
MD_MAX72XX *pM = nullptr;
|
||||
void modulesOnOff(uint8_t start,
|
||||
uint8_t end,
|
||||
MD_MAX72XX::controlValue_t on_off);
|
||||
# endif // ifdef P104_USE_BAR_GRAPH
|
||||
|
||||
bool logAllText = false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user