Merge branch 'mega' into feature/BME680_playground

This commit is contained in:
TD-er
2020-12-13 14:56:03 +01:00
committed by GitHub
22 changed files with 527 additions and 291 deletions
+5
View File
@@ -683,6 +683,11 @@ size_t OLEDDisplay::write(const char* str) {
return length;
}
void OLEDDisplay::SetComPins(uint8_t _compins) {
sendCommand(SETCOMPINS);
sendCommand(_compins); // according to the adafruit lib, sometimes this may need to be 0x02
}
// Private functions
void OLEDDisplay::sendInitCommands(void) {
sendCommand(DISPLAYOFF);
+5
View File
@@ -213,6 +213,11 @@ class OLEDDisplay : public Print {
// Normal display mode
void normalDisplay(void);
// Command to set the COM signals pin configuration to match the OLED panel hardware layout
// 128x64 and 64x48 _compins should be 0x12 (alread set during init())
// 128x32 _compins should be 0x02
void SetComPins(uint8_t _compins);
// Set display contrast
// really low brightness & contrast: contrast = 10, precharge = 5, comdetect = 0
// normal brightness & contrast: contrast = 100
@@ -1,24 +1,17 @@
#ifndef OLED_SSD1306_SH1106_IMAGES_H
#define OLED_SSD1306_SH1106_IMAGES_H
#define espeasy_logo_width 36
#define espeasy_logo_height 36
#define espeasy_logo_width 32
#define espeasy_logo_height 32
const char espeasy_logo_bits[] PROGMEM= {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x60, 0x40, 0xc0, 0x00, 0x00, 0x70, 0xf0, 0xe0,
0x01, 0x00, 0x78, 0xf8, 0xf0, 0x01, 0x00, 0x3c, 0x7c, 0xf8, 0x00, 0x00,
0x1e, 0x3e, 0x7c, 0x00, 0x00, 0x0f, 0x1f, 0x3e, 0x00, 0x80, 0x87, 0x0f,
0x1f, 0x00, 0xc0, 0xc3, 0x87, 0x0f, 0x00, 0xe0, 0xe1, 0xc3, 0x07, 0x00,
0xf0, 0xf0, 0xe1, 0xc3, 0x00, 0x78, 0xf8, 0xf0, 0xe1, 0x01, 0x30, 0x7c,
0xf8, 0xf0, 0x00, 0x00, 0x3e, 0x7c, 0x78, 0x00, 0x00, 0x1f, 0x3e, 0x3c,
0x00, 0x80, 0x0f, 0x1f, 0x1e, 0x00, 0xc0, 0x87, 0x0f, 0x0f, 0x00, 0xe0,
0xc3, 0x87, 0x07, 0x00, 0xf0, 0xe1, 0xc3, 0x03, 0x00, 0xf0, 0xf0, 0xe1,
0x01, 0x00, 0x78, 0xf8, 0xf0, 0x00, 0x00, 0x30, 0x7c, 0x78, 0x00, 0x00,
0x00, 0x3e, 0x3c, 0x00, 0x00, 0x00, 0x1f, 0x1e, 0x00, 0x00, 0x80, 0x0f,
0x0f, 0x78, 0x00, 0xc0, 0x87, 0x07, 0xfc, 0x00, 0xe0, 0xc3, 0x03, 0xfc,
0x01, 0xf0, 0xe1, 0x01, 0xfc, 0x01, 0xf8, 0xf0, 0x00, 0xfc, 0x00, 0x78,
0x70, 0x00, 0x78, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x10, 0x30, 0x00, 0x1c, 0x3c, 0x78, 0x00, 0x1e, 0x3e, 0x7c,
0x00, 0x0f, 0x1f, 0x3e, 0x80, 0x87, 0x0f, 0x1f, 0xc0, 0xc3, 0x87, 0x0f, 0xe0, 0xe1, 0xc3, 0x07,
0xf0, 0xf0, 0xe1, 0x03, 0x78, 0xf8, 0xf0, 0x01, 0x3c, 0x7c, 0xf8, 0x30, 0x1e, 0x3e, 0x7c, 0x78,
0x0c, 0x1f, 0x3e, 0x3c, 0x80, 0x0f, 0x1f, 0x1e, 0xc0, 0x87, 0x0f, 0x0f, 0xe0, 0xc3, 0x87, 0x07,
0xf0, 0xe1, 0xc3, 0x03, 0xf8, 0xf0, 0xe1, 0x01, 0x7c, 0xf8, 0xf0, 0x00, 0x3c, 0x7c, 0x78, 0x00,
0x1e, 0x3e, 0x3c, 0x00, 0x0c, 0x1f, 0x1e, 0x00, 0x80, 0x0f, 0x0f, 0x00, 0xc0, 0x87, 0x07, 0x00,
0xe0, 0xc3, 0x03, 0x1e, 0xf0, 0xe1, 0x01, 0x3f, 0xf8, 0xf0, 0x00, 0x7f, 0x7c, 0x78, 0x00, 0x7f,
0x3e, 0x3c, 0x00, 0x3f, 0x1e, 0x1c, 0x00, 0x1e, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
const char activeSymbole[] PROGMEM = {
B00000000,
+113 -14
View File
@@ -14,6 +14,14 @@
// Added to the main repository with some optimizations and some limitations.
// Al long as the device is not selected, no RAM is waisted.
//
// @uwekaditz: 2020-10-19
// CHG: ressouce-saving string calculation
// @uwekaditz: 2020-10-211
// NEW: Support for 128x32 displays (see https://www.letscontrolit.com/forum/viewtopic.php?p=39840#p39840)
// NEW: Option to hide the header
// CHG: Calculate font setting, if necessary reduce lines per page (fonts are not longer a fixed setting)
// CHG: Reduce espeasy_logo to 32x32 to fit all displays
// CHG: Calculate font setting for splash screen
// @uwekaditz: 2020-06-22
// BUG: MaxFramesToDisplay was not updated if all display lines were empty -> display_indicator() crashed due to memory overflow
// CHG: MaxFramesToDisplay will be updated after receiving command with new line content
@@ -180,6 +188,7 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
1,
P036_data_struct::getDisplaySizeSettings(tOLEDIndex).MaxLines);
}
addFormNote(F("Will be automatically reduced if there is no font to fit this setting."));
{
uint8_t choice = P036_SCROLL;
@@ -201,6 +210,28 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
// FIXME TD-er: Why is this using pin3 and not pin1? And why isn't this using the normal pin selection functions?
addFormPinSelect(F("Display button"), F("taskdevicepin3"), CONFIG_PIN3);
bool tbPin3Invers = bitRead(PCONFIG_LONG(0), 16); // Bit 16
{
uint8_t choice = uint8_t(bitRead(PCONFIG_LONG(0), 26)); // Bit 26 Input PullUp
int Opcount = 2;
#ifdef INPUT_PULLDOWN
choice += uint8_t(bitRead(PCONFIG_LONG(0), 27)) * 2; // Bit 27 Input PullDown
if (choice > 2) {
choice = 2;
}
Opcount = 3;
#endif
String options[3];
options[0] = F("Input");
options[1] = F("Input pullup");
options[2] = F("Input pulldown");
int optionValues[3] =
{ static_cast<int>(eP036pinmode::ePPM_Input),
static_cast<int>(eP036pinmode::ePPM_InputPullUp),
static_cast<int>(eP036pinmode::ePPM_InputPullDown) };
addFormSelector(F("Pin mode"), F("p036_pinmode"), Opcount, options, optionValues, choice);
}
addFormCheckBox(F("Inversed Logic"), F("p036_pin3invers"), tbPin3Invers);
bool bStepThroughPages = bitRead(PCONFIG_LONG(0), 19); // Bit 19
addFormCheckBox(F("Step through frames with Display button"), F("p036_StepPages"), bStepThroughPages);
@@ -228,6 +259,9 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
addFormSubHeader(F("Content"));
bool tbHideHeader = bitRead(PCONFIG_LONG(0), 25); // Bit 25
addFormCheckBox(F("Hide header"), F("p036_HideHeader"), tbHideHeader);
{
uint8_t choice9 = get8BitFromUL(PCONFIG_LONG(0), 8); // Bit15-8 HeaderContent
uint8_t choice10 = get8BitFromUL(PCONFIG_LONG(0), 0); // Bit7-0 HeaderContentAlternative
@@ -271,9 +305,13 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
uint8_t version = get4BitFromUL(PCONFIG_LONG(0), 20); // Bit23-20 Version CustomTaskSettings
P036_data->loadDisplayLines(event->TaskIndex, version);
String strLabel;
for (uint8_t varNr = 0; varNr < P36_Nlines; varNr++)
{
addFormTextBox(String(F("Line ")) + (varNr + 1),
strLabel = F("Line ");
strLabel += (varNr + 1);
addFormTextBox(strLabel,
getPluginCustomArgName(varNr),
String(P036_data->DisplayLinesV1[varNr].Content),
P36_NcharsV1 - 1);
@@ -317,6 +355,21 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
set4BitToUL(lSettings, 20, 0x01); // Bit23-20 Version CustomTaskSettings ->
// version V1
bitWrite(lSettings, 24, !isFormItemChecked(F("p036_ScrollWithoutWifi"))); // Bit 24 ScrollWithoutWifi
bitWrite(lSettings, 25, isFormItemChecked(F("p036_HideHeader"))); // Bit 25 Hide header
int P036pinmode = getFormItemInt(F("p036_pinmode"));
switch (P036pinmode) {
case 1:
{
bitWrite(lSettings, 26, true); // Bit 26 Input PullUp
break;
}
case 2:
{
bitWrite(lSettings, 27, true); // Bit 27 Input PullDown
break;
}
}
PCONFIG_LONG(0) = lSettings;
@@ -358,7 +411,7 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
// After saving, make sure the active lines are updated.
P036_data->frameCounter = 0;
P036_data->MaxFramesToDisplay = 0xFF;
P036_data->_disp_resolution = static_cast<p036_resolution>(P036_RESOLUTION);
P036_data->disp_resolution = static_cast<p036_resolution>(P036_RESOLUTION);
P036_data->loadDisplayLines(event->TaskIndex, 1);
}
@@ -382,6 +435,8 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
// Load the custom settings from flash
uint8_t version = get4BitFromUL(PCONFIG_LONG(0), 20); // Bit23-20 Version CustomTaskSettings
P036_data->bHideHeader = bitRead(PCONFIG_LONG(0), 25); // Bit 25 Hide header
// Init the display and turn it on
if (!(P036_data->init(event->TaskIndex,
version,
@@ -406,7 +461,22 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
if (CONFIG_PIN3 != -1) // Button related setup
{
pinMode(CONFIG_PIN3, INPUT_PULLUP);
#ifdef INPUT_PULLDOWN
if (bitRead(PCONFIG_LONG(0), 27)) { // Bit 27 Input PullDown
pinMode(CONFIG_PIN3, INPUT_PULLDOWN); // Reset pinstate to PIN_MODE_INPUT_PULLDOWN
}
else
#endif
{
if (bitRead(PCONFIG_LONG(0), 26)) { // Bit 26 Input PullUp
pinMode(CONFIG_PIN3, INPUT_PULLUP); // Reset pinstate to PIN_MODE_INPUT_PULLUP
}
else {
pinMode(CONFIG_PIN3, INPUT); // Reset pinstate to PIN_MODE_INPUT
}
}
P036_data->DebounceCounter = 0;
P036_data->RepeatCounter = 0;
P036_data->ButtonState = false;
@@ -487,7 +557,22 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
P036_data->P036_JumpToPage(event, 0); // Start to display the first page, function needs 65ms!
}
P036_data->markButtonStateProcessed();
pinMode(CONFIG_PIN3, INPUT_PULLUP); // Reset pinstate
#ifdef INPUT_PULLDOWN
if (bitRead(PCONFIG_LONG(0), 27)) { // Bit 27 Input PullDown
pinMode(CONFIG_PIN3, INPUT_PULLDOWN); // Reset pinstate to PIN_MODE_INPUT_PULLDOWN
}
else
#endif
{
if (bitRead(PCONFIG_LONG(0), 26)) { // Bit 26 Input PullUp
pinMode(CONFIG_PIN3, INPUT_PULLUP); // Reset pinstate to PIN_MODE_INPUT_PULLUP
}
else {
pinMode(CONFIG_PIN3, INPUT); // Reset pinstate to PIN_MODE_INPUT
}
}
}
if (P036_data->bLineScrollEnabled) {
@@ -722,7 +807,10 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
uint16_t PixLength = P036_data->display->getStringWidth(String(P036_data->DisplayLinesV1[LineNo - 1].Content));
if (PixLength > 255) {
addHtmlError(String(F("Pixel length of ")) + String(PixLength) + String(F(" too long for line! Max. 255 pix!")));
String str_error = F("Pixel length of ");
str_error += PixLength;
str_error += F(" too long for line! Max. 255 pix!");
addHtmlError(str_error);
int strlen = String(P036_data->DisplayLinesV1[LineNo - 1].Content).length();
float fAvgPixPerChar = ((float)PixLength) / strlen;
@@ -749,12 +837,20 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
}
#ifdef PLUGIN_036_DEBUG
String log = String(F("[P36] Line: ")) + String(LineNo);
log += String(F(" NewContent:")) + String(NewContent);
log += String(F(" Content:")) + String(P036_data->DisplayLinesV1[LineNo - 1].Content);
log += String(F(" Length:")) + String(String(P036_data->DisplayLinesV1[LineNo - 1].Content).length());
log += String(F(" Pix: ")) + String(P036_data->display->getStringWidth(String(P036_data->DisplayLinesV1[LineNo - 1].Content)));
log += String(F(" Reserved:")) + String(P036_data->DisplayLinesV1[LineNo - 1].reserved);
String log;
log.reserve(200); // estimated
log = F("[P36] Line: ");
log += LineNo;
log += F(" NewContent:");
log += NewContent;
log += F(" Content:");
log += String(P036_data->DisplayLinesV1[LineNo - 1].Content);
log += F(" Length:");
log += P036_data->DisplayLinesV1[LineNo - 1].Content).length();
log += F(" Pix: ");
log += P036_data->display->getStringWidth(String(P036_data->DisplayLinesV1[LineNo - 1].Content));
log += F(" Reserved:");
log += P036_data->DisplayLinesV1[LineNo - 1].reserved;
addLog(LOG_LEVEL_INFO, log);
#endif // PLUGIN_036_DEBUG
}
@@ -762,9 +858,12 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string)
#ifdef PLUGIN_036_DEBUG
if (!success) {
String log = String(F("[P36] Cmd: ")) + String(command);
log += String(F(" SubCmd:")) + String(subcommand);
log += String(F(" Success:")) + jsonBool(success);
String log = F("[P36] Cmd: ");
log += command;
log += F(" SubCmd:");
log += subcommand;
log += F(" Success:"):
log += jsonBool(success);
addLog(LOG_LEVEL_INFO, log);
}
#endif // PLUGIN_036_DEBUG
+37 -36
View File
@@ -120,22 +120,29 @@ bool checkSourceFlags(EventValueSource::Enum source, EventValueSourceGroup::Enum
return false;
}
bool do_command_case(const String & cmd_lc,
const char *cmd,
struct EventStruct *event,
const char *line,
String & status,
command_case_data::command_case_data(const char *cmd, struct EventStruct *event, const char *line) :
cmd(cmd), event(event), line(line)
{
cmd_lc = cmd;
cmd_lc.toLowerCase();
}
bool do_command_case(command_case_data & data,
const String & cmd_test,
command_function pFunc,
int nrArguments,
EventValueSourceGroup::Enum group,
bool & retval)
EventValueSourceGroup::Enum group)
{
if (!cmd_lc.equals(cmd_test)) {
// The data struct is re-used on each attempt to process an internal command.
// Re-initialize the only two members that may have been altered by a previous call.
data.retval = false;
data.status = "";
if (!data.cmd_lc.equals(cmd_test)) {
return false;
}
if (!checkSourceFlags(event->Source, group)) {
status = return_incorrect_source();
if (!checkSourceFlags(data.event->Source, group)) {
data.status = return_incorrect_source();
return false;
}
// FIXME TD-er: Do not check nr arguments from MQTT source.
@@ -143,42 +150,36 @@ bool do_command_case(const String & cmd_lc,
// C005 does recreate command partly from topic and published message
// e.g. ESP_Easy/Bathroom_pir_env/GPIO/14 with data 0 or 1
// This only allows for 2 parameters, but some commands need more arguments (default to "0")
const bool mustCheckNrArguments = event->Source != EventValueSource::Enum::VALUE_SOURCE_MQTT;
const bool mustCheckNrArguments = data.event->Source != EventValueSource::Enum::VALUE_SOURCE_MQTT;
if (mustCheckNrArguments) {
if (!checkNrArguments(cmd, line, nrArguments)) {
status = return_incorrect_nr_arguments();
retval = false;
if (!checkNrArguments(data.cmd, data.line, nrArguments)) {
data.status = return_incorrect_nr_arguments();
data.retval = false;
return true; // Command is handled
}
}
status = pFunc(event, line);
retval = true;
data.status = pFunc(data.event, data.line);
data.retval = true;
return true; // Command is handled
}
bool executeInternalCommand(const char *cmd, struct EventStruct *event, const char *line, String& status)
bool executeInternalCommand(command_case_data & data)
{
String cmd_lc;
cmd_lc = cmd;
cmd_lc.toLowerCase();
bool retval;
// Simple macro to match command to function call.
// EventValueSourceGroup::Enum::ALL
#define COMMAND_CASE_A(S, C, NARGS) \
if (do_command_case(cmd_lc, cmd, event, line, status, F(S), &C, NARGS, EventValueSourceGroup::Enum::ALL, retval)) { return retval; }
if (do_command_case(data, F(S), &C, NARGS, EventValueSourceGroup::Enum::ALL)) { return data.retval; }
// EventValueSourceGroup::Enum::RESTRICTED
#define COMMAND_CASE_R(S, C, NARGS) \
if (do_command_case(cmd_lc, cmd, event, line, status, F(S), &C, NARGS, EventValueSourceGroup::Enum::RESTRICTED, retval)) { return retval; }
if (do_command_case(data, F(S), &C, NARGS, EventValueSourceGroup::Enum::RESTRICTED)) { return data.retval; }
// FIXME TD-er: Should we execute command when number of arguments is wrong?
// FIXME TD-er: must determine nr arguments where NARGS is set to -1
switch (cmd_lc[0]) {
switch (data.cmd_lc[0]) {
case 'a': {
COMMAND_CASE_A("accessinfo", Command_AccessInfo_Ls, 0); // Network Command
COMMAND_CASE_A("asyncevent", Command_Rules_Async_Events, -1); // Rule.h
@@ -266,7 +267,7 @@ bool executeInternalCommand(const char *cmd, struct EventStruct *event, const ch
break;
}
case 'm': {
if (cmd_lc[1] == 'c') {
if (data.cmd_lc[1] == 'c') {
COMMAND_CASE_A( "mcpgpio", Command_GPIO, 2); // Gpio.h
COMMAND_CASE_A( "mcpgpiotoggle", Command_GPIO_Toggle, 1); // Gpio.h
COMMAND_CASE_A( "mcplongpulse", Command_GPIO_LongPulse, 3); // GPIO.h
@@ -290,7 +291,7 @@ bool executeInternalCommand(const char *cmd, struct EventStruct *event, const ch
break;
}
case 'p': {
if (cmd_lc[1] == 'c') {
if (data.cmd_lc[1] == 'c') {
COMMAND_CASE_A( "pcfgpio", Command_GPIO, 2); // Gpio.h
COMMAND_CASE_A( "pcfgpiotoggle", Command_GPIO_Toggle, 1); // Gpio.h
COMMAND_CASE_A( "pcflongpulse", Command_GPIO_LongPulse, 3); // GPIO.h
@@ -321,7 +322,7 @@ bool executeInternalCommand(const char *cmd, struct EventStruct *event, const ch
COMMAND_CASE_R("sdremove", Command_SD_Remove, 1); // SDCARDS.h
#endif // ifdef FEATURE_SD
if (cmd_lc[1] == 'e') {
if (data.cmd_lc[1] == 'e') {
COMMAND_CASE_A( "sendto", Command_UPD_SendTo, 2); // UDP.h // FIXME TD-er: These send commands, can we determine the nr
// of
// arguments?
@@ -344,7 +345,7 @@ bool executeInternalCommand(const char *cmd, struct EventStruct *event, const ch
break;
}
case 't': {
if (cmd_lc[1] == 'a') {
if (data.cmd_lc[1] == 'a') {
COMMAND_CASE_R( "taskclear", Command_Task_Clear, 1); // Tasks.h
COMMAND_CASE_R("taskclearall", Command_Task_ClearAll, 0); // Tasks.h
COMMAND_CASE_R( "taskdisable", Command_Task_Disable, 1); // Tasks.h
@@ -353,7 +354,7 @@ bool executeInternalCommand(const char *cmd, struct EventStruct *event, const ch
COMMAND_CASE_A( "taskvalueset", Command_Task_ValueSet, 3); // Tasks.h
COMMAND_CASE_A( "taskvaluetoggle", Command_Task_ValueToggle, 2); // Tasks.h
COMMAND_CASE_A("taskvaluesetandrun", Command_Task_ValueSetAndRun, 3); // Tasks.h
} else if (cmd_lc[1] == 'i') {
} else if (data.cmd_lc[1] == 'i') {
COMMAND_CASE_A( "timerpause", Command_Timer_Pause, 1); // Timers.h
COMMAND_CASE_A("timerresume", Command_Timer_Resume, 1); // Timers.h
COMMAND_CASE_A( "timerset", Command_Timer_Set, 2); // Timers.h
@@ -375,7 +376,7 @@ bool executeInternalCommand(const char *cmd, struct EventStruct *event, const ch
COMMAND_CASE_R("wdconfig", Command_WD_Config, 3); // WD.h
COMMAND_CASE_R( "wdread", Command_WD_Read, 2); // WD.h
if (cmd_lc[1] == 'i') {
if (data.cmd_lc[1] == 'i') {
COMMAND_CASE_R( "wifiapmode", Command_Wifi_APMode, 0); // WiFi.h
COMMAND_CASE_A( "wificonnect", Command_Wifi_Connect, 0); // WiFi.h
COMMAND_CASE_A("wifidisconnect", Command_Wifi_Disconnect, 0); // WiFi.h
@@ -513,12 +514,12 @@ bool ExecuteCommand(taskIndex_t taskIndex,
if (tryInternal) {
String status;
bool handled = executeInternalCommand(cmd.c_str(), &TempEvent, action.c_str(), status);
command_case_data data(cmd.c_str(), &TempEvent, action.c_str());
bool handled = executeInternalCommand(data);
if (status.length() > 0) {
if (data.status.length() > 0) {
delay(0);
SendStatus(source, status);
SendStatus(source, data.status);
delay(0);
}
+23 -2
View File
@@ -4,19 +4,40 @@
#include "../DataStructs/ESPEasy_EventStruct.h"
#include "../Globals/Plugins.h"
#include <Arduino.h>
bool checkSourceFlags(EventValueSource::Enum source, EventValueSourceGroup::Enum group);
bool checkNrArguments(const char *cmd, const char *Line, int nrArguments);
// Typedef for function pointer to be called for handling an internal command.
typedef String (*command_function)(struct EventStruct *, const char *);
bool do_command_case(const String& cmd_lc, const char *cmd, struct EventStruct *event, const char *line, String& status, const String& cmd_test, command_function pFunc, int nrArguments, EventValueSourceGroup::Enum group, bool& retval);
// Simple struct to be used in handling commands.
// By packing all into a struct, the macro calling do_command_case generates a lot less code
// resulting in a smaller binary.
struct command_case_data {
command_case_data(const char *cmd, struct EventStruct *event, const char *line);
String cmd_lc;
const char *cmd;
struct EventStruct *event;
const char *line;
String status;
bool retval = false;
};
bool do_command_case(command_case_data& data, const String& cmd_test, command_function pFunc, int nrArguments, EventValueSourceGroup::Enum group);
/*********************************************************************************************\
* Registers command
\*********************************************************************************************/
bool executeInternalCommand(const char *cmd, struct EventStruct *event, const char *line, String& status);
bool executeInternalCommand(command_case_data & data);
// Execute command which may be plugin or internal commands
+7
View File
@@ -66,6 +66,9 @@ To create/register a plugin, you have to :
#ifndef WEBSERVER_CONTROLLERS
#define WEBSERVER_CONTROLLERS
#endif
#ifndef WEBSERVER_CUSTOM
#define WEBSERVER_CUSTOM
#endif
#ifndef WEBSERVER_DEVICES
#define WEBSERVER_DEVICES
#endif
@@ -332,6 +335,10 @@ To create/register a plugin, you have to :
#ifdef WEBSERVER_WIFI_SCANNER
#undef WEBSERVER_WIFI_SCANNER
#endif
#ifdef WEBSERVER_CUSTOM
#undef WEBSERVER_CUSTOM
#endif
#endif // WEBSERVER_CUSTOM_BUILD_DEFINED
#ifndef LIMIT_BUILD_SIZE
-36
View File
@@ -1,36 +0,0 @@
#include "LongTermTimer.h"
#include "ESPEasy_time_calc.h"
uint64_t LongTermTimer::get() const {
return _timer_usec;
}
void LongTermTimer::setNow() {
_timer_usec = getMicros64();
}
LongTermTimer::Duration LongTermTimer::timeDiff(const LongTermTimer& next) const {
return __timeDiff(_timer_usec, next.get());
}
LongTermTimer::Duration LongTermTimer::usecPassedSince() const {
return __timeDiff(_timer_usec, getMicros64());
}
LongTermTimer::Duration LongTermTimer::millisPassedSince() const {
return usecPassedSince() / 1000ll;
}
bool LongTermTimer::timeReached() const {
return getMicros64() > _timer_usec;
}
bool LongTermTimer::timeoutReached(uint32_t millisTimeout) const {
return getMicros64() > (_timer_usec + (millisTimeout * 1000ull));
}
LongTermTimer::Duration LongTermTimer::__timeDiff(uint64_t prev, uint64_t next) {
return static_cast<int64_t>(next) - static_cast<int64_t>(prev);
}
+27 -9
View File
@@ -3,6 +3,8 @@
#include <Arduino.h>
#include "ESPEasy_time_calc.h"
class LongTermTimer {
public:
@@ -48,24 +50,40 @@ public:
return _timer_usec > 0ull;
}
uint64_t ICACHE_RAM_ATTR get() const;
uint64_t get() const {
return _timer_usec;
}
void ICACHE_RAM_ATTR setNow();
void setNow() {
_timer_usec = getMicros64();
}
// Positive when next is past this time value.
Duration ICACHE_RAM_ATTR timeDiff(const LongTermTimer& next) const;
Duration timeDiff(const LongTermTimer& next) const {
return __timeDiff(_timer_usec, next.get());
}
Duration ICACHE_RAM_ATTR usecPassedSince() const;
Duration ICACHE_RAM_ATTR millisPassedSince() const;
Duration usecPassedSince() const {
return __timeDiff(_timer_usec, getMicros64());
}
bool ICACHE_RAM_ATTR timeReached() const;
Duration millisPassedSince() const {
return usecPassedSince() / 1000ll;
}
bool ICACHE_RAM_ATTR timeoutReached(uint32_t millisTimeout) const;
bool timeReached() const {
return getMicros64() > _timer_usec;
}
bool timeoutReached(uint32_t millisTimeout) const {
return getMicros64() > (_timer_usec + (millisTimeout * 1000ull));
}
private:
static Duration ICACHE_RAM_ATTR __timeDiff(uint64_t prev,
uint64_t next);
static Duration __timeDiff(uint64_t prev, uint64_t next) {
return static_cast<int64_t>(next) - static_cast<int64_t>(prev);
}
uint64_t _timer_usec = 0ull;
};
+1 -1
View File
@@ -31,7 +31,7 @@ void set_mDNS() {
}
if (mdns_started) {
MDNS.addService("http", "tcp", Settings.WebserverPort);
MDNS.addService(F("http"), F("tcp"), Settings.WebserverPort);
}
}
#endif // ifdef FEATURE_MDNS
+7 -7
View File
@@ -36,13 +36,13 @@ HandledWebCommand_result handle_command_from_web(EventValueSource::Enum source,
eventQueue.add(parseStringToEnd(webrequest, 2));
handledCmd = true;
sendOK = true;
} else if (command.equalsIgnoreCase(F("taskrun")) ||
command.equalsIgnoreCase(F("taskvalueset")) ||
command.equalsIgnoreCase(F("taskvaluetoggle")) ||
command.equalsIgnoreCase(F("let")) ||
command.equalsIgnoreCase(F("logPortStatus")) ||
command.equalsIgnoreCase(F("jsonportstatus")) ||
command.equalsIgnoreCase(F("rules"))) {
} else if (command.equals(F("taskrun")) ||
command.equals(F("taskvalueset")) ||
command.equals(F("taskvaluetoggle")) ||
command.equals(F("let")) ||
command.equals(F("logPortStatus")) ||
command.equals(F("jsonportstatus")) ||
command.equals(F("rules"))) {
handledCmd = ExecuteCommand_internal(source, webrequest.c_str());
sendOK = true;
+2 -1
View File
@@ -243,10 +243,11 @@ void serialHelper_webformLoad(ESPEasySerialPort port, int rxPinDef, int txPinDef
if (Settings.UseSerial) {
addFormNote(F("Do <b>NOT</b> combine HW Serial0 and log to serial on Tools->Advanced->Serial Port."));
}
#ifdef ESP8266
if ((rxPinDef == 15) || (txPinDef == 15)) {
addFormNote(F("GPIO-15 (D8) requires a Buffer Circuit (PNP transistor) or ESP boot may fail."));
}
#endif
}
void serialHelper_webformSave(byte& port, int8_t& rxPin, int8_t& txPin) {
+231 -121
View File
@@ -28,39 +28,25 @@ void P036_data_struct::reset() {
}
}
const tFontSizes FontSizes[P36_MaxFontCount] = {
{ ArialMT_Plain_24, 24, 28},
{ ArialMT_Plain_16, 16, 19},
{ Dialog_plain_12, 13, 15},
{ ArialMT_Plain_10, 10, 13}
};
const tSizeSettings SizeSettings[P36_MaxSizesCount] = {
{ P36_MaxDisplayWidth, P36_MaxDisplayHeight, 0, // 128x64
4,
// page scrolling height = 42
{ 19, ArialMT_Plain_24, 28 }, // Width: 24 Height: 28
{ 15, ArialMT_Plain_16, 19 }, // Width: 16 Height: 19
{ 12, Dialog_plain_12, 14 }, // Width: 13 Height: 15
{ 12, ArialMT_Plain_10, 10 }, // Width: 10 Height: 13
113,
15
4, // max. line count
113, 15 // WiFi indicator
},
{ P36_MaxDisplayWidth, 32, 0, // 128x32
2,
// page scrolling height = 20
{ 14, Dialog_plain_12, 15 }, // Width: 13 Height: 15
{ 12, ArialMT_Plain_10, 10 }, // Width: 10 Height: 13
{ 0, ArialMT_Plain_10, 0 }, // Width: 10 Height: 13 not used!
{ 0, ArialMT_Plain_10, 0 }, // Width: 10 Height: 13 not used!
113,
15
2, // max. line count
113, 15 // WiFi indicator
},
{ 64, 48, 32, // 64x48
3,
// page scrolling height = 36
{ 20, ArialMT_Plain_24, 28 }, // Width: 24 Height: 28
{ 14, Dialog_plain_12, 17 }, // Width: 13 Height: 15
{ 13, ArialMT_Plain_10, 11 }, // Width: 10 Height: 13
{ 0, ArialMT_Plain_10, 0 }, // Width: 10 Height: 13 not used!
32,
10
3, // max. line count
32, 10 // WiFi indicator
}
};
@@ -75,19 +61,19 @@ const tSizeSettings& P036_data_struct::getDisplaySizeSettings(p036_resolution di
bool P036_data_struct::init(taskIndex_t taskIndex,
uint8_t LoadVersion,
uint8_t _type,
uint8_t _address,
uint8_t _sda,
uint8_t _scl,
p036_resolution disp_resolution,
bool _rotated,
uint8_t contrast,
uint8_t _displayTimer,
uint8_t nrLines) {
uint8_t Type,
uint8_t Address,
uint8_t Sda,
uint8_t Scl,
p036_resolution Disp_resolution,
bool Rotated,
uint8_t Contrast,
uint8_t DisplayTimer,
uint8_t NrLines) {
reset();
lastWiFiState = P36_WIFI_STATE_UNSET;
_disp_resolution = p036_resolution::pix128x64;
disp_resolution = p036_resolution::pix128x64;
bAlternativHeader = false; // start with first header content
HeaderCount = 0;
bPageScrollDisabled = true; // first page after INIT without scrolling
@@ -104,16 +90,16 @@ bool P036_data_struct::init(taskIndex_t taskIndex,
DebounceCounter = 0; // debounce counter
RepeatCounter = 0; // Repeat delay counter when holding button pressed
displayTimer = _displayTimer;
displayTimer = DisplayTimer;
frameCounter = 0; // need to keep track of framecounter from call to call
disableFrameChangeCnt = 0; // counter to disable frame change after JumpToPage in case PLUGIN_READ already scheduled
switch (_type) {
switch (Type) {
case 1:
display = new (std::nothrow) SSD1306Wire(_address, _sda, _scl);
display = new (std::nothrow) SSD1306Wire(Address, Sda, Scl);
break;
case 2:
display = new (std::nothrow) SH1106Wire(_address, _sda, _scl);
display = new (std::nothrow) SH1106Wire(Address, Sda, Scl);
break;
default:
return false;
@@ -121,17 +107,25 @@ bool P036_data_struct::init(taskIndex_t taskIndex,
if (display != nullptr) {
display->init(); // call to local override of init function
disp_resolution = Disp_resolution;
bHideFooter = !(getDisplaySizeSettings(disp_resolution).Height == P36_MaxDisplayHeight);
if (disp_resolution == p036_resolution::pix128x32) {
display->displayOff();
display->SetComPins(0x02); // according to the adafruit lib, sometimes this may need to be 0x02
bHideFooter = true;
}
display->displayOn();
loadDisplayLines(taskIndex, LoadVersion);
_disp_resolution = disp_resolution;
// Flip screen if required
setOrientationRotated(_rotated);
setOrientationRotated(Rotated);
setContrast(contrast);
setContrast(Contrast);
// Display the device name, logo, time and wifi
display_header();
display_logo();
update_display();
@@ -140,7 +134,7 @@ bool P036_data_struct::init(taskIndex_t taskIndex,
currentFrameToDisplay = 0;
nextFrameToDisplay = 0;
bPageScrollDisabled = true; // first page after INIT without scrolling
ScrollingPages.linesPerFrame = nrLines;
ScrollingPages.linesPerFrame = NrLines;
bLineScrollEnabled = false; // start without line scrolling
// Clear scrolling line data
@@ -215,7 +209,7 @@ void P036_data_struct::setContrast(uint8_t OLED_contrast) {
void P036_data_struct::setOrientationRotated(bool rotated) {
if (rotated) {
display->flipScreenVertically();
TopLineOffset = P36_MaxDisplayHeight - getDisplaySizeSettings(_disp_resolution).Height;
TopLineOffset = P36_MaxDisplayHeight - getDisplaySizeSettings(disp_resolution).Height;
} else {
TopLineOffset = 0;
}
@@ -225,19 +219,22 @@ void P036_data_struct::display_header() {
if (!isInitialized()) {
return;
}
if (bHideHeader) { // hide header
return;
}
eHeaderContent _HeaderContent;
eHeaderContent iHeaderContent;
String newString, strHeader;
if ((HeaderContentAlternative == HeaderContent) || !bAlternativHeader) {
_HeaderContent = HeaderContent;
iHeaderContent = HeaderContent;
}
else
{
_HeaderContent = HeaderContentAlternative;
iHeaderContent = HeaderContentAlternative;
}
switch (_HeaderContent) {
switch (iHeaderContent) {
case eHeaderContent::eSSID:
if (NetworkConnected()) {
@@ -306,7 +303,7 @@ void P036_data_struct::display_header() {
display_title(strHeader);
// Display time and wifibars both clear area below, so paint them after the title.
if (getDisplaySizeSettings(_disp_resolution).Width == P36_MaxDisplayWidth) {
if (getDisplaySizeSettings(disp_resolution).Width == P36_MaxDisplayWidth) {
display_time(); // only for 128pix wide displays
}
display_wifibars();
@@ -323,7 +320,7 @@ void P036_data_struct::display_time() {
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(ArialMT_Plain_10);
display->setColor(BLACK);
display->fillRect(0, TopLineOffset, 28, P36_HeaderHeight - 2);
display->fillRect(0, TopLineOffset, 28, GetHeaderHeight() - 2);
display->setColor(WHITE);
display->drawString(0, TopLineOffset, dtime.substring(0, 5));
}
@@ -334,16 +331,16 @@ void P036_data_struct::display_title(const String& title) {
}
display->setFont(ArialMT_Plain_10);
display->setColor(BLACK);
display->fillRect(0, TopLineOffset, P36_MaxDisplayWidth, P36_HeaderHeight); // don't clear line under title.
display->fillRect(0, TopLineOffset, P36_MaxDisplayWidth, GetHeaderHeight()); // don't clear line under title.
display->setColor(WHITE);
if (getDisplaySizeSettings(_disp_resolution).Width == P36_MaxDisplayWidth) {
if (getDisplaySizeSettings(disp_resolution).Width == P36_MaxDisplayWidth) {
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(P36_DisplayCentre, TopLineOffset, title);
}
else {
display->setTextAlignment(TEXT_ALIGN_LEFT); // Display right of WiFi bars
display->drawString(getDisplaySizeSettings(_disp_resolution).PixLeft + getDisplaySizeSettings(_disp_resolution).WiFiIndicatorWidth + 3,
display->drawString(getDisplaySizeSettings(disp_resolution).PixLeft + getDisplaySizeSettings(disp_resolution).WiFiIndicatorWidth + 3,
TopLineOffset,
title);
}
@@ -353,20 +350,27 @@ void P036_data_struct::display_logo() {
if (!isInitialized()) {
return;
}
# ifdef PLUGIN_036_DEBUG
addLog(LOG_LEVEL_INFO, F("P036_DisplayLogo"));
# endif // PLUGIN_036_DEBUG
int left = 24;
int top;
tFontSettings iFontsettings = CalculateFontSettings(2); // get font with max. height for displaying "ESP Easy"
bDisplayingLogo = true; // next time the display must be cleared completely
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(ArialMT_Plain_16);
display->setColor(BLACK);
display->fillRect(0, P36_HeaderHeight + 1 + TopLineOffset, P36_MaxDisplayWidth, P36_MaxDisplayHeight);
display->setFont(iFontsettings.fontData);
display->clear(); // resets all pixels to black
display->setColor(WHITE);
display->drawString(65, 15 + TopLineOffset, F("ESP"));
display->drawString(65, 34 + TopLineOffset, F("Easy"));
display->drawString(65, iFontsettings.Top + TopLineOffset, F("ESP"));
display->drawString(65, iFontsettings.Top + iFontsettings.Height + iFontsettings.Space + TopLineOffset, F("Easy"));
if (getDisplaySizeSettings(_disp_resolution).PixLeft < left) { left = getDisplaySizeSettings(_disp_resolution).PixLeft; }
if (getDisplaySizeSettings(disp_resolution).PixLeft < left) { left = getDisplaySizeSettings(disp_resolution).PixLeft; }
top = (getDisplaySizeSettings(disp_resolution).Height-espeasy_logo_height)/2;
if (top < 0) { top = 0; }
display->drawXbm(left,
P36_HeaderHeight + 1 + TopLineOffset,
top+TopLineOffset,
espeasy_logo_width,
espeasy_logo_height,
espeasy_logo_bits); // espeasy_logo_width=espeasy_logo_height=36
@@ -378,6 +382,10 @@ void P036_data_struct::display_indicator() {
if (!isInitialized()) {
return;
}
if (bHideFooter) { // hide footer
return;
}
int frameCount = MaxFramesToDisplay + 1;
// Erase Indicator Area
@@ -425,41 +433,133 @@ void P036_data_struct::display_indicator() {
}
}
int16_t P036_data_struct::GetHeaderHeight()
{
if (bHideHeader) {
// no header
return 0;
}
return P36_HeaderHeight;
}
int16_t P036_data_struct::GetIndicatorTop()
{
if (bHideFooter) {
// no footer (indicator) -> returm max. display height
return getDisplaySizeSettings(disp_resolution).Height;
}
return P036_IndicatorTop;
}
tFontSettings P036_data_struct::CalculateFontSettings(uint8_t lDefaultLines)
{
tFontSettings result;
int iHeight;
int8_t iFontIndex = -1;
uint8_t iMaxHeightForFont;
uint8_t iLinesPerFrame;
if (lDefaultLines == 0)
{
// number of lines can be reduced if no font fits the setting
iLinesPerFrame = ScrollingPages.linesPerFrame;
iHeight = GetIndicatorTop() - GetHeaderHeight();
}
else
{
// number of lines is fixed (e.g. for splash screen)
iLinesPerFrame = lDefaultLines;
iHeight = getDisplaySizeSettings(disp_resolution).Height;
}
while (iFontIndex < 0) {
iMaxHeightForFont = (iHeight - (iLinesPerFrame - 1)) / iLinesPerFrame; // at least 1 pixel space between lines
for (uint8_t i = P36_MaxFontCount; i > 0; i--) {
// check available fonts for the line setting
if (FontSizes[i-1].Height > iMaxHeightForFont) {
// height of font is to big
break;
}
iFontIndex = i-1; // save the current index
if (FontSizes[iFontIndex].Height == iMaxHeightForFont) {
// height of font just fits the line setting
break;
}
}
if (iFontIndex < 0) {
// no font fits -> reduce number of lines per page
iLinesPerFrame--;
if (iLinesPerFrame == 0) {
// lines per frame is at minimum
break;
}
}
}
if (iFontIndex >= 0) {
// font found -> calculate top position and space between lines
iMaxHeightForFont = FontSizes[iFontIndex].Height * iLinesPerFrame;
if (iLinesPerFrame > 1) {
// more than one lines per frame -> calculate space inbetween
result.Space = (iHeight-iMaxHeightForFont) / iLinesPerFrame;
}
else {
// just one lines per frame -> no space inbetween
result.Space = 0;
}
result.Top = (iHeight - (iMaxHeightForFont + (result.Space * (iLinesPerFrame-1)))) / 2;
}
else {
// no font found -> return font with shortest height
result.Top = 0;
result.Space = 1;
iLinesPerFrame = 1;
iFontIndex = P36_MaxFontCount-1;
}
result.fontData = FontSizes[iFontIndex].fontData;
result.Height = FontSizes[iFontIndex].Height;
# ifdef PLUGIN_036_DEBUG
String log;
log.reserve(128); // estimated
log = F("CalculateFontSettings: FontIndex:");
log += iFontIndex;
log += F(" Top:");
log += result.Top;
log += F(" FontHeight:");
log += result.Height;
log += F(" Space:");
log += result.Space;
log += F(" Height:");
log += iHeight;
log += F(" LinesPerFrame:");
log += iLinesPerFrame;
log += F(" DefaultLines:");
log += lDefaultLines;
addLog(LOG_LEVEL_INFO, log);
# endif // PLUGIN_036_DEBUG
if (lDefaultLines == 0)
ScrollingPages.linesPerFrame = iLinesPerFrame;
return result;
}
void P036_data_struct::prepare_pagescrolling()
{
if (!isInitialized()) {
return;
}
switch (ScrollingPages.linesPerFrame) {
case 1:
ScrollingPages.Font = getDisplaySizeSettings(_disp_resolution).L1.fontData;
ScrollingPages.ypos[0] = getDisplaySizeSettings(_disp_resolution).L1.Top + TopLineOffset;
ScrollingLines.Space = getDisplaySizeSettings(_disp_resolution).L1.Space + 1;
break;
case 2:
ScrollingPages.Font = getDisplaySizeSettings(_disp_resolution).L2.fontData;
ScrollingPages.ypos[0] = getDisplaySizeSettings(_disp_resolution).L2.Top + TopLineOffset;
ScrollingPages.ypos[1] = ScrollingPages.ypos[0] + getDisplaySizeSettings(_disp_resolution).L2.Space;
ScrollingLines.Space = getDisplaySizeSettings(_disp_resolution).L2.Space + 1;
break;
case 3:
ScrollingPages.Font = getDisplaySizeSettings(_disp_resolution).L3.fontData;
ScrollingPages.ypos[0] = getDisplaySizeSettings(_disp_resolution).L3.Top + TopLineOffset;
ScrollingPages.ypos[1] = ScrollingPages.ypos[0] + getDisplaySizeSettings(_disp_resolution).L3.Space;
ScrollingPages.ypos[2] = ScrollingPages.ypos[1] + getDisplaySizeSettings(_disp_resolution).L3.Space;
ScrollingLines.Space = getDisplaySizeSettings(_disp_resolution).L3.Space + 1;
break;
default:
ScrollingPages.linesPerFrame = 4;
ScrollingPages.Font = getDisplaySizeSettings(_disp_resolution).L4.fontData;
ScrollingPages.ypos[0] = getDisplaySizeSettings(_disp_resolution).L4.Top + TopLineOffset;
ScrollingPages.ypos[1] = ScrollingPages.ypos[0] + getDisplaySizeSettings(_disp_resolution).L4.Space;
ScrollingPages.ypos[2] = ScrollingPages.ypos[1] + getDisplaySizeSettings(_disp_resolution).L4.Space;
ScrollingPages.ypos[3] = ScrollingPages.ypos[2] + getDisplaySizeSettings(_disp_resolution).L4.Space;
ScrollingLines.Space = getDisplaySizeSettings(_disp_resolution).L4.Space + 1;
}
ScrollingLines.Font = ScrollingPages.Font;
tFontSettings iFontsettings = CalculateFontSettings(0);
ScrollingPages.Font = iFontsettings.fontData;
ScrollingPages.ypos[0] = iFontsettings.Top + GetHeaderHeight() + TopLineOffset;
ScrollingPages.ypos[1] = ScrollingPages.ypos[0] + iFontsettings.Height + iFontsettings.Space;
ScrollingPages.ypos[2] = ScrollingPages.ypos[1] + iFontsettings.Height + iFontsettings.Space;
ScrollingPages.ypos[3] = ScrollingPages.ypos[2] + iFontsettings.Height + iFontsettings.Space;
ScrollingLines.Font = ScrollingPages.Font;
ScrollingLines.Space = iFontsettings.Height + iFontsettings.Space + 1;
for (uint8_t i = 0; i < P36_MAX_LinesPerPage; i++) {
ScrollingLines.Line[i].ypos = ScrollingPages.ypos[i];
@@ -479,8 +579,10 @@ uint8_t P036_data_struct::display_scroll(ePageScrollSpeed lscrollspeed, int lTas
int iCharToRemove;
# ifdef PLUGIN_036_DEBUG
String log = F("Start Scrolling: Speed: ");
log += lscrollspeed;
String log;
log.reserve(128); // estimated
log = F("Start Scrolling: Speed: ");
log += ((int) lscrollspeed);
addLog(LOG_LEVEL_INFO, log);
# endif // PLUGIN_036_DEBUG
@@ -495,7 +597,7 @@ uint8_t P036_data_struct::display_scroll(ePageScrollSpeed lscrollspeed, int lTas
} else {
iPageScrollTime = (P36_MaxDisplayWidth / (P36_PageScrollPix * static_cast<int>(lscrollspeed))) * P36_PageScrollTick;
}
float fScrollTime = (float)(lTaskTimer * 1000 - iPageScrollTime - 2 * P36_WaitScrollLines * 100) / 100.0f;
int iScrollTime = (float)(lTaskTimer * 1000 - iPageScrollTime - 2 * P36_WaitScrollLines * 100) / 100; // scrollTime in ms
# ifdef PLUGIN_036_DEBUG
log = F("PageScrollTime: ");
@@ -507,7 +609,7 @@ uint8_t P036_data_struct::display_scroll(ePageScrollSpeed lscrollspeed, int lTas
if (bLineScrollEnabled) {
// Reduced scrolling width because line is displayed left or right aligned
MaxPixWidthForPageScrolling -= getDisplaySizeSettings(_disp_resolution).PixLeft;
MaxPixWidthForPageScrolling -= getDisplaySizeSettings(disp_resolution).PixLeft;
}
for (uint8_t j = 0; j < ScrollingPages.linesPerFrame; j++)
@@ -540,20 +642,20 @@ uint8_t P036_data_struct::display_scroll(ePageScrollSpeed lscrollspeed, int lTas
if (bLineScrollEnabled) {
// settings for following line scrolling
if (PixLengthLineOut > getDisplaySizeSettings(_disp_resolution).Width) {
if (PixLengthLineOut > getDisplaySizeSettings(disp_resolution).Width) {
ScrollingLines.Line[j].LastWidth = PixLengthLineOut; // while page scrolling this line is right aligned
}
if ((PixLengthLineIn > getDisplaySizeSettings(_disp_resolution).Width) && (fScrollTime > 0.0f))
if ((PixLengthLineIn > getDisplaySizeSettings(disp_resolution).Width) && (iScrollTime > 0))
{
// width of the line > display width -> scroll line
ScrollingLines.Line[j].LineContent = ScrollingPages.LineIn[j];
ScrollingLines.Line[j].Width = PixLengthLineIn; // while page scrolling this line is left aligned
ScrollingLines.Line[j].CurrentLeft = getDisplaySizeSettings(_disp_resolution).PixLeft;
ScrollingLines.Line[j].fPixSum = (float)getDisplaySizeSettings(_disp_resolution).PixLeft;
ScrollingLines.Line[j].CurrentLeft = getDisplaySizeSettings(disp_resolution).PixLeft;
ScrollingLines.Line[j].fPixSum = (float)getDisplaySizeSettings(disp_resolution).PixLeft;
// pix change per scrolling line tick
ScrollingLines.Line[j].dPix = ((float)(PixLengthLineIn - getDisplaySizeSettings(_disp_resolution).Width)) / fScrollTime;
ScrollingLines.Line[j].dPix = ((float)(PixLengthLineIn - getDisplaySizeSettings(disp_resolution).Width)) / iScrollTime;
# ifdef PLUGIN_036_DEBUG
log = String(F("Line: ")) + String(j + 1);
@@ -648,15 +750,17 @@ uint8_t P036_data_struct::display_scroll(ePageScrollSpeed lscrollspeed, int lTas
ScrollingPages.dPixSum = ScrollingPages.dPix;
display->setColor(BLACK);
// We allow 12 pixels at the top because otherwise the wifi indicator gets too squashed!!
// scrolling window is 42 pixels high - ie 64 less margin of 12 at top and 10 at bottom
display->fillRect(0, P36_HeaderHeight + TopLineOffset, P36_MaxDisplayWidth, P036_IndicatorTop - P36_HeaderHeight);
display->fillRect(0, GetHeaderHeight() + TopLineOffset, P36_MaxDisplayWidth, GetIndicatorTop() - GetHeaderHeight());
display->setColor(WHITE);
display->drawLine(0,
P36_HeaderHeight + TopLineOffset,
P36_MaxDisplayWidth,
P36_HeaderHeight + TopLineOffset); // line below title
if (!bHideHeader) {
display->drawLine(0,
GetHeaderHeight() + TopLineOffset,
P36_MaxDisplayWidth,
GetHeaderHeight() + TopLineOffset); // line below title
}
for (uint8_t j = 0; j < ScrollingPages.linesPerFrame; j++)
{
@@ -664,7 +768,7 @@ uint8_t P036_data_struct::display_scroll(ePageScrollSpeed lscrollspeed, int lTas
if (ScrollingLines.Line[j].LastWidth > 0) {
// width of LineOut[j] > display width -> line at beginning of scrolling page is right aligned
display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->drawString(P36_MaxDisplayWidth - getDisplaySizeSettings(_disp_resolution).PixLeft + ScrollingPages.dPixSum,
display->drawString(P36_MaxDisplayWidth - getDisplaySizeSettings(disp_resolution).PixLeft + ScrollingPages.dPixSum,
ScrollingPages.ypos[j],
ScrollingPages.LineOut[j]);
}
@@ -680,7 +784,7 @@ uint8_t P036_data_struct::display_scroll(ePageScrollSpeed lscrollspeed, int lTas
if (ScrollingLines.Line[j].Width > 0) {
// width of LineIn[j] > display width -> line at end of scrolling page should be left aligned
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(-P36_MaxDisplayWidth + getDisplaySizeSettings(_disp_resolution).PixLeft + ScrollingPages.dPixSum,
display->drawString(-P36_MaxDisplayWidth + getDisplaySizeSettings(disp_resolution).PixLeft + ScrollingPages.dPixSum,
ScrollingPages.ypos[j],
ScrollingPages.LineIn[j]);
}
@@ -720,7 +824,7 @@ uint8_t P036_data_struct::display_scroll_timer() {
// We allow 13 pixels (including underline) at the top because otherwise the wifi indicator gets too squashed!!
// scrolling window is 42 pixels high - ie 64 less margin of 12 at top and 10 at bottom
display->fillRect(0, P36_HeaderHeight + 1 + TopLineOffset, P36_MaxDisplayWidth, P036_IndicatorTop - P36_HeaderHeight);
display->fillRect(0, GetHeaderHeight() + 1 + TopLineOffset, P36_MaxDisplayWidth, GetIndicatorTop() - GetHeaderHeight());
display->setColor(WHITE);
display->setFont(ScrollingPages.Font);
@@ -729,7 +833,7 @@ uint8_t P036_data_struct::display_scroll_timer() {
if (ScrollingLines.Line[j].LastWidth > 0) {
// width of LineOut[j] > display width -> line is right aligned while scrolling page
display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->drawString(P36_MaxDisplayWidth - getDisplaySizeSettings(_disp_resolution).PixLeft + ScrollingPages.dPixSum,
display->drawString(P36_MaxDisplayWidth - getDisplaySizeSettings(disp_resolution).PixLeft + ScrollingPages.dPixSum,
ScrollingPages.ypos[j],
ScrollingPages.LineOut[j]);
}
@@ -744,7 +848,7 @@ uint8_t P036_data_struct::display_scroll_timer() {
if (ScrollingLines.Line[j].Width > 0) {
// width of LineIn[j] > display width -> line is left aligned while scrolling page
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(-P36_MaxDisplayWidth + getDisplaySizeSettings(_disp_resolution).PixLeft + ScrollingPages.dPixSum,
display->drawString(-P36_MaxDisplayWidth + getDisplaySizeSettings(disp_resolution).PixLeft + ScrollingPages.dPixSum,
ScrollingPages.ypos[j],
ScrollingPages.LineIn[j]);
}
@@ -815,8 +919,8 @@ void P036_data_struct::display_scrolling_lines() {
ScrollingLines.Space + 1); // clearing window was too high
display->setColor(WHITE);
if (((ScrollingLines.Line[i].CurrentLeft - getDisplaySizeSettings(_disp_resolution).PixLeft) +
ScrollingLines.Line[i].Width) >= getDisplaySizeSettings(_disp_resolution).Width) {
if (((ScrollingLines.Line[i].CurrentLeft - getDisplaySizeSettings(disp_resolution).PixLeft) +
ScrollingLines.Line[i].Width) >= getDisplaySizeSettings(disp_resolution).Width) {
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(ScrollingLines.Line[i].CurrentLeft,
ScrollingLines.Line[i].ypos,
@@ -825,7 +929,7 @@ void P036_data_struct::display_scrolling_lines() {
else {
// line scrolling finished -> line is shown as aligned right
display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->drawString(P36_MaxDisplayWidth - getDisplaySizeSettings(_disp_resolution).PixLeft,
display->drawString(P36_MaxDisplayWidth - getDisplaySizeSettings(disp_resolution).PixLeft,
ScrollingPages.ypos[i],
ScrollingLines.Line[i].LineContent);
ScrollingLines.Line[i].Width = 0; // Stop scrolling
@@ -843,6 +947,9 @@ bool P036_data_struct::display_wifibars() {
if (!isInitialized()) {
return false;
}
if (bHideHeader) { // hide header
return false;
}
const bool connected = NetworkConnected();
const int nbars_filled = (WiFi.RSSI() + 100) / 12; // all bars filled if RSSI better than -46dB
@@ -851,10 +958,10 @@ bool P036_data_struct::display_wifibars() {
if (newState == lastWiFiState) {
return false; // nothing to do.
}
int x = getDisplaySizeSettings(_disp_resolution).WiFiIndicatorLeft;
int x = getDisplaySizeSettings(disp_resolution).WiFiIndicatorLeft;
int y = TopLineOffset;
int size_x = getDisplaySizeSettings(_disp_resolution).WiFiIndicatorWidth;
int size_y = P36_HeaderHeight - 2;
int size_x = getDisplaySizeSettings(disp_resolution).WiFiIndicatorWidth;
int size_y = GetHeaderHeight() - 2;
int nbars = 5;
int16_t width = (size_x / nbars);
@@ -1024,13 +1131,16 @@ void P036_data_struct::P036_DisplayPage(struct EventStruct *event)
}
// Update display
if (bDisplayingLogo) {
bDisplayingLogo = false;
display->clear(); // resets all pixels to black
}
bAlternativHeader = false; // start with first header content
HeaderCount = 0; // reset header count
display_header();
if (getDisplaySizeSettings(_disp_resolution).Width == P36_MaxDisplayWidth) {
display_indicator();
}
display_indicator();
update_display();
+31 -14
View File
@@ -15,6 +15,7 @@
#define P36_NcharsV0 32 // max chars per line up to 22.11.2019 (V0)
#define P36_NcharsV1 64 // max chars per line from 22.11.2019 (V1)
#define P36_MaxSizesCount 3 // number of different OLED sizes
#define P36_MaxFontCount 4 // number of different fonts
#define P36_MaxDisplayWidth 128
#define P36_MaxDisplayHeight 64
@@ -71,6 +72,12 @@ enum class ePageScrollSpeed {
ePSS_Instant = 32 // 20ms
};
enum class eP036pinmode {
ePPM_Input = 0,
ePPM_InputPullUp = 1,
ePPM_InputPullDown = 2
};
typedef struct {
String LineContent; // content
uint16_t LastWidth = 0; // width of last line in pix
@@ -109,10 +116,16 @@ typedef struct {
uint8_t reserved = 0;
} tDisplayLines;
typedef struct {
const char *fontData; // font
uint8_t Width; // font width in pix
uint8_t Height; // font height in pix
} tFontSizes;
typedef struct {
uint8_t Top; // top in pix for this line setting
const char *fontData; // font for this line setting
uint8_t Height; // font height in pix
uint8_t Space; // space in pix between lines for this line setting
} tFontSettings;
@@ -121,10 +134,6 @@ typedef struct {
uint8_t Height; // height in pix
uint8_t PixLeft; // first left pix position
uint8_t MaxLines; // max. line count
tFontSettings L1; // settings for 1 line
tFontSettings L2; // settings for 2 lines
tFontSettings L3; // settings for 3 lines
tFontSettings L4; // settings for 4 lines
uint8_t WiFiIndicatorLeft; // left of WiFi indicator
uint8_t WiFiIndicatorWidth; // width of WiFi indicator
} tSizeSettings;
@@ -140,15 +149,15 @@ struct P036_data_struct : public PluginTaskData_base {
bool init(taskIndex_t taskIndex,
uint8_t LoadVersion,
uint8_t _type,
uint8_t _address,
uint8_t _sda,
uint8_t _scl,
p036_resolution disp_resolution,
bool _rotated,
uint8_t contrast,
uint8_t _displayTimer,
uint8_t nrLines);
uint8_t Type,
uint8_t Address,
uint8_t Sda,
uint8_t Scl,
p036_resolution Disp_resolution,
bool Rotated,
uint8_t Contrast,
uint8_t DisplayTimer,
uint8_t NrLines);
bool isInitialized() const;
@@ -187,6 +196,11 @@ struct P036_data_struct : public PluginTaskData_base {
// Perform the actual write to the display.
void update_display();
// get pixel positions
int16_t GetHeaderHeight();
int16_t GetIndicatorTop();
tFontSettings CalculateFontSettings(uint8_t _defaultLines);
void P036_JumpToPage(struct EventStruct *event,
uint8_t nextFrame);
@@ -210,9 +224,10 @@ struct P036_data_struct : public PluginTaskData_base {
tDisplayLines DisplayLinesV1[P36_Nlines]; // holds the CustomTaskSettings for V1
int8_t lastWiFiState = 0;
bool bDisplayingLogo = false;
// display
p036_resolution _disp_resolution = p036_resolution::pix128x64;
p036_resolution disp_resolution = p036_resolution::pix128x64;
bool bLineScrollEnabled = false;
uint8_t TopLineOffset = 0; // Offset for top line, used for rotated image while using displays < P36_MaxDisplayHeight lines
// Display button
@@ -222,6 +237,8 @@ struct P036_data_struct : public PluginTaskData_base {
uint8_t RepeatCounter = 0; // Repeat delay counter when holding button pressed
uint8_t displayTimer = 0; // counter for display OFF
// frame header
bool bHideHeader = false;
bool bHideFooter = false;
bool bAlternativHeader = false;
uint16_t HeaderCount = 0;
eHeaderContent HeaderContent = eHeaderContent::eSSID;
+2 -2
View File
@@ -1,10 +1,10 @@
#include "../WebServer/AdvancedConfigPage.h"
#include "../WebServer/WebServer.h"
#include "../WebServer/HTML_wrappers.h"
#include "../WebServer/Markup.h"
#include "../WebServer/Markup_Buttons.h"
#include "../WebServer/Markup_Forms.h"
#include "../WebServer/WebServer.h"
#include "../Globals/ESPEasy_time.h"
#include "../Globals/Settings.h"
@@ -54,7 +54,7 @@ void handle_advanced() {
TimeChangeRule dst_end(dstendweek, dstenddow, dstendmonth, dstendhour, timezone);
if (dst_end.isValid()) { Settings.DST_End = dst_end.toFlashStoredValue(); }
str2ip(web_server.arg(F("syslogip")).c_str(), Settings.Syslog_IP);
webArg2ip(F("syslogip"), Settings.Syslog_IP);
Settings.WebserverPort = getFormItemInt(F("webport"));
Settings.UDPPort = getFormItemInt(F("udpport"));
+11 -28
View File
@@ -2,12 +2,12 @@
#ifdef WEBSERVER_CONFIG
#include "../WebServer/WebServer.h"
#include "../WebServer/HTML_wrappers.h"
#include "../WebServer/AccessControl.h"
#include "../WebServer/Markup.h"
#include "../WebServer/Markup_Buttons.h"
#include "../WebServer/Markup_Forms.h"
#include "../WebServer/WebServer.h"
#include "../ESPEasyCore/Controller.h"
@@ -41,22 +41,8 @@ void handle_config() {
String name = web_server.arg(F("name"));
name.trim();
// String password = web_server.arg(F("password"));
String iprangelow = web_server.arg(F("iprangelow"));
String iprangehigh = web_server.arg(F("iprangehigh"));
Settings.Delay = getFormItemInt(F("delay"), Settings.Delay);
Settings.deepSleep_wakeTime = getFormItemInt(F("awaketime"), Settings.deepSleep_wakeTime);
String espip = web_server.arg(F("espip"));
String espgateway = web_server.arg(F("espgateway"));
String espsubnet = web_server.arg(F("espsubnet"));
String espdns = web_server.arg(F("espdns"));
#ifdef HAS_ETHERNET
String espethip = web_server.arg(F("espethip"));
String espethgateway = web_server.arg(F("espethgateway"));
String espethsubnet = web_server.arg(F("espethsubnet"));
String espethdns = web_server.arg(F("espethdns"));
#endif
Settings.Unit = getFormItemInt(F("unit"), Settings.Unit);
// String apkey = web_server.arg(F("apkey"));
@@ -112,24 +98,21 @@ void handle_config() {
case ONLY_IP_RANGE_ALLOWED:
case ALL_ALLOWED:
// iprangelow.toCharArray(tmpString, 26);
str2ip(iprangelow, SecuritySettings.AllowedIPrangeLow);
// iprangehigh.toCharArray(tmpString, 26);
str2ip(iprangehigh, SecuritySettings.AllowedIPrangeHigh);
webArg2ip(F("iprangelow"), SecuritySettings.AllowedIPrangeLow);
webArg2ip(F("iprangehigh"), SecuritySettings.AllowedIPrangeHigh);
break;
}
Settings.deepSleepOnFail = isFormItemChecked(F("deepsleeponfail"));
str2ip(espip, Settings.IP);
str2ip(espgateway, Settings.Gateway);
str2ip(espsubnet, Settings.Subnet);
str2ip(espdns, Settings.DNS);
webArg2ip(F("espip"), Settings.IP);
webArg2ip(F("espgateway"), Settings.Gateway);
webArg2ip(F("espsubnet"), Settings.Subnet);
webArg2ip(F("espdns"), Settings.DNS);
#ifdef HAS_ETHERNET
str2ip(espethip, Settings.ETH_IP);
str2ip(espethgateway, Settings.ETH_Gateway);
str2ip(espethsubnet, Settings.ETH_Subnet);
str2ip(espethdns, Settings.ETH_DNS);
webArg2ip(F("espethip"), Settings.ETH_IP);
webArg2ip(F("espethgateway"), Settings.ETH_Gateway);
webArg2ip(F("espethsubnet"), Settings.ETH_Subnet);
webArg2ip(F("espethdns"), Settings.ETH_DNS);
#endif
addHtmlError(SaveSettings());
}
+4
View File
@@ -18,6 +18,8 @@
#include "../../_Plugin_Helper.h"
#ifdef WEBSERVER_CUSTOM
// ********************************************************************************
// Web Interface custom page handler
// ********************************************************************************
@@ -200,3 +202,5 @@ boolean handle_custom(String path) {
TXBuffer.endStream();
return true;
}
#endif
+2 -1
View File
@@ -3,10 +3,11 @@
#include "../WebServer/common.h"
#ifdef WEBSERVER_CUSTOM
// ********************************************************************************
// Web Interface custom page handler
// ********************************************************************************
boolean handle_custom(String path);
#endif
#endif
+2
View File
@@ -43,7 +43,9 @@ bool loadFromFS(boolean spiffs, String path) {
else if (path.endsWith(F(".json"))) { dataType = F("application/json"); }
else if (path.endsWith(F(".txt")) ||
path.endsWith(F(".dat"))) { dataType = F("application/octet-stream"); }
#ifdef WEBSERVER_CUSTOM
else if (path.endsWith(F(".esp"))) { return handle_custom(path); }
#endif
#ifndef BUILD_NO_DEBUG
+2 -2
View File
@@ -130,7 +130,7 @@ void handle_sysvars() {
for (byte i = 0; i < CUSTOM_VARS_MAX; ++i) {
addSysVar_html("%v" + toString(i + 1, 0) + '%');
}
#ifndef BUILD_NO_SPECIAL_CHARACTERS_STRINGCONVERTER
addTableSeparator(F("Special Characters"), 3, 2);
addTableSeparator(F("Degree"), 3, 3);
addSysVar_html(F("{D}"));
@@ -185,7 +185,7 @@ void handle_sysvars() {
addFormSeparator(3);
addSysVar_html(F("{..}"));
addSysVar_html(F("&divide;"));
#endif
addTableSeparator(F("Standard Conversions"), 3, 2);
addSysVar_html(F("Wind Dir.: %c_w_dir%(123.4)"));
+4
View File
@@ -1188,3 +1188,7 @@ void getPartitionTableSVG(byte pType, unsigned int partitionColor) {
}
#endif // ifdef ESP32
bool webArg2ip(const String& arg, byte *IP) {
return str2ip(web_server.arg(arg), IP);
}
+1
View File
@@ -161,5 +161,6 @@ void getPartitionTableSVG(byte pType, unsigned int partitionColor);
#endif // ifdef ESP32
bool webArg2ip(const String& arg, byte *IP);
#endif