Nextion display plugin

Moderators: BertB, rtenklooster, Voyager, Stuntteam, Martinus

Message
Author
ThomasB
Normal user
Posts: 57
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#261 Post by ThomasB » 12 Jul 2018, 00:09

The ESP8266 crash/brick (due to deleting the plugin) has been an interesting problem. Much hair pulling!

What I've learned: When the Nextion plugin is deleted (or checkbox disabled), then ESP rebooted, the NEXTION plugin is still partially active at boot and attempts to parse the NEXTION rules (in the rule file). But since the plugin is not officially active, it causes a crash. Here's the boot log:

Code: Select all

INIT : Booting version: (custom) (ESP82xx Core 2_4_1, NONOS SDK 2.2.1(cfd48f3), LWIP: 2.0.3)
101 : INIT : Warm boot #15 - Restart Reason: Exception
105 : FS   : Mounting...
130 : FS   : Mount successful, used 77057 bytes of 957314
141 : CRC  : No program memory checksum found. Check output of crc2.py
172 : CRC  : SecuritySettings CRC   ...OK
275 : INIT : Free RAM:21640
276 : INIT : I2C
276 : INIT : SPI not enabled
296 : INFO : Plugins: 71 [Normal] [Testing] (ESP82xx Core 2_4_1, NONOS SDK 2.2.1(cfd48f3), LWIP: 2.0.3)
297 : EVENT: System#Wake
320 : WIFI : Set WiFi to STA
352 : WIFI : Connecting Wizard1_2G4 attempt #0
353 : IP   : Static IP : THIS LINE DELETED BY THOMASB
366 : EVENT: System#Boot
389 : SW   : Switch state 1 Output value 0
392 : EVENT: WASHER#ac=0.00
402 : ACT  : NEXTION,page0.va_WasherAC.val=0

Exception (28):
epc1=0x40259086 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000

ctx: cont
          sp: 3fff3c50 end: 3fff46b0 offset: 01a0
Deleting the NEXTION rules before the reboot prevents the crash/brick. This is why my full flash erase "fixed" the problem (because it erased the rule file too).

But despite some coding drama, I haven't found out why the deleted/disabled plugin is in this zombie state. I would expect it to ignore NEXTION activity. So I could use some advice on what to do about this.
Seems like the ESP is extremely busy doing something, but I can't see what, because ... No serial port.
From the outside, the esp seems to be extremely slow, not to say dead.
I experience this problem after I have rebooted the ESP8266 too many times. All the ESP WiFi login/reconnects eventually cause my wireless router to slow down ALL wireless connection. I have to reboot my router to get back to normal.

- Thomas

ThomasB
Normal user
Posts: 57
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#262 Post by ThomasB » 12 Jul 2018, 04:56

@BertB
I found a line of code that needs correction.

Find this:

Code: Select all

boolean Plugin_075(byte function, struct EventStruct *event, String &string) {
and change it to:

Code: Select all

boolean Plugin_075(byte function, struct EventStruct *event, String& string) {
I'm not sure if the compiler sees the two statements in the say way. So best to make the edit just in case.

- Thomas

User avatar
grovkillen
Normal user
Posts: 1619
Joined: 19 Jan 2017, 12:56
Location: Hudiksvall, Sweden
Contact:

Re: Nextion display plugin

#263 Post by grovkillen » 12 Jul 2018, 09:59

The problem with deleting the plugin might be related to the fact that you are using HW serial?
ESP Easy Flasher [flash tool and wifi setup at flash time]
ESP Easy Webdumper [easy screendumping of your units]
ESP Easy Netscan [find units]
:idea: Sponsor ESP Easy :idea:

ThomasB
Normal user
Posts: 57
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#264 Post by ThomasB » 12 Jul 2018, 20:42

grovkillen wrote:
12 Jul 2018, 09:59
The problem with deleting the plugin might be related to the fact that you are using HW serial?
That was my expectation too. But disabling HW serial was a dead end. So much hair pulling!

I've reorganized the PLUGIN_ states in the Nextion plugin so that they are all in the same order as found in the master plugin template (_Pxxx_PluginTemplate.ino). This has stopped the crash/brick when the Nextion plugin was deleted/disabled.

I looked at the system's PluginCall() function to see why reordering the states fixed the problem but I can't find an explanation. So I will continue to monitor the issue in case it returns. I have a dreaded feeling that it will bite back again.

I've made several code changes and added some new features. I'll post the new code later today to try out.

- Thomas

User avatar
grovkillen
Normal user
Posts: 1619
Joined: 19 Jan 2017, 12:56
Location: Hudiksvall, Sweden
Contact:

Re: Nextion display plugin

#265 Post by grovkillen » 12 Jul 2018, 20:50

Thanks for all your efforts!
ESP Easy Flasher [flash tool and wifi setup at flash time]
ESP Easy Webdumper [easy screendumping of your units]
ESP Easy Netscan [find units]
:idea: Sponsor ESP Easy :idea:

BertB
Normal user
Posts: 947
Joined: 25 Apr 2015, 14:39

Re: Nextion display plugin

#266 Post by BertB » 12 Jul 2018, 23:02

It is hard to believe that the order of the states could make that kind of problems. Unless there is some kind of a memory or a stack problem..

ThomasB
Normal user
Posts: 57
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#267 Post by ThomasB » 13 Jul 2018, 16:14

I'm worried about it too.

There's some hints that memory problems are possible in my ESPEasy builds. When I compile (Arduino 1.8.5) I see a number of uninitialized variable warnings in the libraries. The letscontrolit tutorial is using version Arduino 1.6.12. It would be cruel to have to do it, but do I need to install that old version?

Here's the compiler output with Compiler Warning level set to "more":

Code: Select all

WARNING: Category 'LED' in library CHT16K33 LED Matrix Library is not valid. Setting to 'Uncategorized'
WARNING: Category 'Input' in library MechInputs is not valid. Setting to 'Uncategorized'
WARNING: Category 'Input' in library SerialSensors is not valid. Setting to 'Uncategorized'
WARNING: library LiquidCrystal_I2C claims to run on (avr) architecture(s) and may be incompatible with your current board which runs on (esp8266) architecture(s).
D:\Lang\Arduino\Arduino-1.8.5\libraries\AS_BH1750\AS_BH1750A.cpp: In member function 'bool AS_BH1750A::startMeasurementAsync(TimeFuncPtr)':

D:\Lang\Arduino\Arduino-1.8.5\libraries\AS_BH1750\AS_BH1750A.cpp:518:7: warning: unused variable '_lastResult' [-Wunused-variable]

   int _lastResult = -1;

       ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\AS_BH1750\AS_BH1750A.cpp: In member function 'bool AS_BH1750A::delayExpired()':

D:\Lang\Arduino\Arduino-1.8.5\libraries\AS_BH1750\AS_BH1750A.cpp:533:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

   if (timestamp < _lastTimestamp)

                   ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\AS_BH1750\AS_BH1750A.cpp:536:45: warning: statement has no effect [-Wunused-value]

     delayTime = MAX_U_LONG - _lastTimestamp + timestamp;

                                             ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\AS_BH1750\AS_BH1750A.cpp:542:24: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

   return (delayTime >= _nextDelay);

                        ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\IRremoteESP8266\IRremoteESP8266.cpp: In member function 'void IRrecv::copyIrParams(irparams_t*)':

D:\Lang\Arduino\Arduino-1.8.5\libraries\IRremoteESP8266\IRremoteESP8266.cpp:818:36: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

   for (int i=0; i<sizeof(irparams_t); i++)

                                    ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp: In member function 'void Adafruit_StepperMotor::step(uint16_t, uint8_t, uint8_t)':

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp:220:11: warning: variable 'ret' set but not used [-Wunused-but-set-variable]

   uint8_t ret = 0;

           ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp: In member function 'uint8_t Adafruit_StepperMotor::onestep(uint8_t, uint8_t)':

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp:242:11: warning: unused variable 'a' [-Wunused-variable]

   uint8_t a, b, c, d;

           ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp:242:14: warning: unused variable 'b' [-Wunused-variable]

   uint8_t a, b, c, d;

              ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp:242:17: warning: unused variable 'c' [-Wunused-variable]

   uint8_t a, b, c, d;

                 ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp:242:20: warning: unused variable 'd' [-Wunused-variable]

   uint8_t a, b, c, d;

                    ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp: In member function 'Adafruit_DCMotor* Adafruit_MotorShield::getMotor(uint8_t)':

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp:89:31: warning: 'in2' may be used uninitialized in this function [-Wmaybe-uninitialized]

     dcmotors[num].IN2pin = in2;

                               ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp:88:31: warning: 'in1' may be used uninitialized in this function [-Wmaybe-uninitialized]

     dcmotors[num].IN1pin = in1;

                               ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp:87:31: warning: 'pwm' may be used uninitialized in this function [-Wmaybe-uninitialized]

     dcmotors[num].PWMpin = pwm;

                               ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp: In member function 'Adafruit_StepperMotor* Adafruit_MotorShield::getStepper(uint16_t, uint8_t)':

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp:118:33: warning: 'bin2' may be used uninitialized in this function [-Wmaybe-uninitialized]

     steppers[num].BIN2pin = bin2;

                                 ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp:117:33: warning: 'bin1' may be used uninitialized in this function [-Wmaybe-uninitialized]

     steppers[num].BIN1pin = bin1;

                                 ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp:116:33: warning: 'ain2' may be used uninitialized in this function [-Wmaybe-uninitialized]

     steppers[num].AIN2pin = ain2;

                                 ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp:115:33: warning: 'ain1' may be used uninitialized in this function [-Wmaybe-uninitialized]

     steppers[num].AIN1pin = ain1;

                                 ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp:114:33: warning: 'pwmb' may be used uninitialized in this function [-Wmaybe-uninitialized]

     steppers[num].PWMBpin = pwmb;

                                 ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_Motor_Shield_V2\Adafruit_MotorShield.cpp:113:33: warning: 'pwma' may be used uninitialized in this function [-Wmaybe-uninitialized]

     steppers[num].PWMApin = pwma;

                                 ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_TSL2591\Adafruit_TSL2591.cpp: In member function 'float Adafruit_TSL2591::calculateLuxf(uint16_t, uint16_t)':

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_TSL2591\Adafruit_TSL2591.cpp:178:12: warning: unused variable 'chan0' [-Wunused-variable]

   uint32_t chan0, chan1;

            ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_TSL2591\Adafruit_TSL2591.cpp:178:19: warning: unused variable 'chan1' [-Wunused-variable]

   uint32_t chan0, chan1;

                   ^

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_TSL2591\Adafruit_TSL2591.cpp: In member function 'uint32_t Adafruit_TSL2591::getFullLuminosity()':

D:\Lang\Arduino\Arduino-1.8.5\libraries\Adafruit_TSL2591\Adafruit_TSL2591.cpp:274:64: warning: 'y' may be used uninitialized in this function [-Wmaybe-uninitialized]

   y |= read16(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CHAN0_LOW);

                                                                ^

Archiving built core (caching) in: C:\Users\Tom\AppData\Local\Temp\arduino_cache_718776\core\core_esp8266_esp8266_nodemcuv2_CpuFrequency_80,FlashSize_4M3M,LwIPVariant_v2mss536,Debug_Disabled,DebugLevel_None____,FlashErase_none,UploadSpeed_115200_c44f0ab9adf3984af47a3c6f9ac1c151.a
Sketch uses 772644 bytes (73%) of program storage space. Maximum is 1044464 bytes.
Global variables use 52416 bytes (63%) of dynamic memory, leaving 29504 bytes for local variables. Maximum is 81920 bytes.
- Thomas

User avatar
grovkillen
Normal user
Posts: 1619
Joined: 19 Jan 2017, 12:56
Location: Hudiksvall, Sweden
Contact:

Re: Nextion display plugin

#268 Post by grovkillen » 13 Jul 2018, 16:19

We (TD-er and myself) user PlatformIO. So I guess that is the preferred IDE.
ESP Easy Flasher [flash tool and wifi setup at flash time]
ESP Easy Webdumper [easy screendumping of your units]
ESP Easy Netscan [find units]
:idea: Sponsor ESP Easy :idea:

ThomasB
Normal user
Posts: 57
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#269 Post by ThomasB » 13 Jul 2018, 22:37

@grovkillen, Thanks for the recommendation. When this project winds down I'll check out PlatformIO.

@everyone, Below is the revised Nextion Plugin, Version 3. Please try it out and share any issues or improvements.

Some comments:
The code still has the blocking delays in it. But they are dynamic and can range from ~10mS for 9600 Baud to as little as 1mS for 115.2K.

My attempt to eliminate the delays became an E-ticket adventure with an unhappy ending. It's the reason I held off until today to post the new beta release.

Here's the story:
The delay code was eliminated and replaced with a local command processor that parsed the Nextion sentences as a "background" task. Rather than wait ~10mS (and block all other timed events), the new code exits the plugin if the Nextion command sentence is incomplete. It picks up where it left off using the common 10Hz update schedule, so overall it is as fast as the old way but without the blocking.

But it can't work in all applications because while the ESP command processor is collecting bytes from a Nextion packet sentence, another rule or timer event can send a command to the Nextion. That's not a problem on its own, but the Nextion will respond by sending its status result code (typically 0x01). Unfortunately this status code is received by the Nextion Plugin's command processor, which corrupts the pending packet sentence.

The workaround is to ignore the status codes (bytes < 0x09). But then Nextion touch events can't be supported (because they are binary and often have values <0x09). The final solution was to revert back to the delay code. I'm not willing to give up yet. Anyone have any ideas?

- Thomas

Code: Select all

//#######################################################################################################
//#######################################################################################################
//################################### Plugin 075: Nextion <info@sensorio.cz>  ###########################
//###################################   Created on the work of  majklovec     ###########################
//###################################    Revisions by BertB and ThomasB       ########################### 
//###################################    Last Revision: July-13-2018 (TB)     ###########################
//#######################################################################################################

#ifdef USES_P075

#include <ESPeasySoftwareSerial.h>

// *****************************************************************************************************
// Defines start here
// *****************************************************************************************************

// Plug-In defines
#define PLUGIN_075
#define PLUGIN_ID_075 75
#define PLUGIN_NAME_075 "Display - Nextion [TESTING_V3]"
#define PLUGIN_VALUENAME1_075 "idx"
#define PLUGIN_VALUENAME2_075 "value"
#define Nlines 12        // Qty of "optional" user entered Command-Text strings, 64 chars max per line.

// Nextion defines
#define RXBUFFSZ  80     // Local Serial RxD buffer.  
#define TOUCH_BASE 500   // Base offset for 0X65 Touch Event.

// Serial defines
#define B9600    0
#define B38400   1
#define B57600   2
#define B115200  3
#define DEFAULT_BAUD B9600

// Global vars
ESPeasySoftwareSerial *SoftSerial = NULL;
int rxPin = -1;
int txPin = -1;


// *****************************************************************************************************
// PlugIn starts here
// *****************************************************************************************************

boolean Plugin_075(byte function, struct EventStruct *event, String& string) 
{
  boolean success = false;
  static boolean HwSerial = false;
  static boolean AdvHwSerial = false;  
  uint32_t AdvHwBaud = 9600UL;

  switch (function) {

    case PLUGIN_DEVICE_ADD: {
      Device[++deviceCount].Number = PLUGIN_ID_075;
      Device[deviceCount].Type = DEVICE_TYPE_DUAL;
      Device[deviceCount].VType = SENSOR_TYPE_DUAL;
      Device[deviceCount].Ports = 0;
      Device[deviceCount].PullUpOption = true;
      Device[deviceCount].InverseLogicOption = false;
      Device[deviceCount].FormulaOption = false;
      Device[deviceCount].ValueCount = 2;
      Device[deviceCount].SendDataOption = true;
      Device[deviceCount].TimerOption = true;
      Device[deviceCount].GlobalSyncOption = true;
      break;
    }


    case PLUGIN_GET_DEVICENAME: {
      string = F(PLUGIN_NAME_075);
      break;
    }


    case PLUGIN_GET_DEVICEVALUENAMES: {
      strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0],PSTR(PLUGIN_VALUENAME1_075));
      strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1],PSTR(PLUGIN_VALUENAME2_075));
      break;
    }


    case PLUGIN_GET_DEVICEGPIONAMES: {

      AdvHwSerial = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
      rxPin = Settings.TaskDevicePin1[event->TaskIndex];
      txPin = Settings.TaskDevicePin2[event->TaskIndex];

      event->String1 = F("GPIO SS RX &larr; ");
      event->String2 = F("GPIO SS TX &rarr; ");

      if(AdvHwSerial == true) {
        if ((rxPin == 3 && txPin == 1) || (rxPin == 13 && txPin == 15)) {
            event->String1 = F("GPIO HW RX &larr; ");
            event->String2 = F("GPIO HW TX &rarr; ");
        }
      }
      break;
    }


    case PLUGIN_WEBFORM_LOAD: {
      rxPin = Settings.TaskDevicePin1[event->TaskIndex];
      txPin = Settings.TaskDevicePin2[event->TaskIndex];

      if (!((rxPin == 3 && txPin == 1) || (rxPin == 13 && txPin == 15))) { // Hardware Serial Compatible?
        Settings.TaskDevicePluginConfig[event->TaskIndex][0] = false;      // Not HW serial compatible, Reset Check Box.
      }
      
      if (rxPin == 3 && txPin == 1) {                                      // USB Port?
        if(Settings.TaskDevicePluginConfig[event->TaskIndex][0]==false &&  // Hardware serial disabled.
         Settings.TaskDeviceEnabled[event->TaskIndex] == true) {        // Plugin is enabled.
            Settings.TaskDevicePluginConfig[event->TaskIndex][0]=true;     // USB port access uses HW serial, Force set Check Box.
        }
      }

      if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == false) {  // Softserial mode. 
        Settings.TaskDevicePluginConfig[event->TaskIndex][1] = B9600;       // Reset to 9600 baud.
      }

      addFormSeparator(2);
      addFormSubHeader(F("Enhanced Serial Communication"));
      addFormCheckBox(F("Use Hardware Serial"), F("AdvHwSerial"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);

      byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
      String options[4];
      options[0] = F("9600");
      options[1] = F("38400");
      options[2] = F("57600");
      options[3] = F("115200");
      
      addFormSelector(F("Baud Rate"), F("plugin_075_baud"), 4, options, NULL, choice);      
      addFormNote(F("Un-check box for Soft Serial communication (low performance mode, 9600 Baud)."));
      addFormNote(F("Hardware Serial is available when the GPIO pins are RX=D7 and TX=D8."));
      addFormNote(F("D8 (GPIO-15) requires a Buffer Circuit (PNP transistor) or ESP boot may fail."));
      addFormNote(F("Do <b>NOT</b> enable the Serial Log file on Tools->Advanced->Serial Port."));
      
//    ** DEVELOPER DEBUG MESSAGE AREA **
//    addFormNote(ExtraTaskSettings.TaskDeviceName); // Debug value.
//    int datax = (int)(Settings.TaskDeviceEnabled[event->TaskIndex]); // Debug value.
//    String Data = "Debug. Plugin Enable State: ";
//    Data += String(datax);
//    addFormNote(Data);


      addFormSubHeader(F("")); // Blank line, vertical space.
      addFormHeader(F("Nextion Command-Text Strings (Optional)"));
      
      char deviceTemplate[Nlines][64];
      LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
      for (byte varNr = 0; varNr < Nlines; varNr++) {
        addFormTextBox(String(F("Line ")) + (varNr + 1), String(F("Plugin_075_template")) + (varNr + 1), deviceTemplate[varNr], 64);
      }

      success = true;
      break;
    }


    case PLUGIN_WEBFORM_SAVE: {

        String argName;

        char deviceTemplate[Nlines][64];
        for (byte varNr = 0; varNr < Nlines; varNr++)
        {
          String arg = F("Plugin_075_template");
          arg += varNr + 1;
          String tmpString = WebServer.arg(arg);
          strncpy(deviceTemplate[varNr], tmpString.c_str(), sizeof(deviceTemplate[varNr])-1);
          deviceTemplate[varNr][63]=0;
        }
        if(ExtraTaskSettings.TaskDeviceName[0]==0) {            // User forgot to enter device name!
            strcpy(ExtraTaskSettings.TaskDeviceName,"NEXTION"); // Give standard name.
        }
        Settings.TaskDevicePluginConfig[event->TaskIndex][0] = isFormItemChecked(F("AdvHwSerial"));
        Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_075_baud"));
        SaveCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));

        success = true;
        break;
    }


    case PLUGIN_INIT: {

      AdvHwSerial = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
      uint8_t BaudCode = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
      
      if(BaudCode > B115200) BaudCode = B9600;
      const uint32_t BaudArray[4] = {9600UL, 38400UL, 57600UL, 115200UL};
      AdvHwBaud = BaudArray[BaudCode];

      if (Settings.TaskDevicePin1[event->TaskIndex] != -1) {
        rxPin = Settings.TaskDevicePin1[event->TaskIndex];
      }
      if (Settings.TaskDevicePin2[event->TaskIndex] != -1) {
        txPin = Settings.TaskDevicePin2[event->TaskIndex];
      }

      if (SoftSerial != NULL) { 
        delete SoftSerial;
        SoftSerial = NULL;
      }

      String log = F("NEXTION075 : serial pin config RX:");
      log += rxPin;
      log += F(", TX:");
      log += txPin;
      if(Settings.TaskDeviceEnabled[event->TaskIndex]==true) 
       log += F(", Plugin Enabled");                    // Plugin is enabled.
      else log += F(", Plugin Disabled");
      addLog(LOG_LEVEL_INFO, log);

      if(Settings.TaskDeviceEnabled[event->TaskIndex] == true) { // Plugin is enabled.
      // Hardware serial is RX on 13 and TX on 15 (swapped hw serial)
        if (AdvHwSerial &&  rxPin == 13 && txPin == 15) {
            log = F("NEXTION075 : Using swap hardware serial");
            addLog(LOG_LEVEL_INFO, log);
            HwSerial = true;
            Settings.UseSerial = false;                 // Disable global Serial port.
            Settings.SerialLogLevel = 0;                // Disable logging on serial port.
            Settings.BaudRate = AdvHwBaud;              // Set BaudRate for Nextion.
            Serial.flush();
            Serial.begin(AdvHwBaud);
            Serial.swap();
        }
        // Hardware serial is RX on 3 and TX on 1. USB serial for Nextion IDE (User MCU Input function).
        else if(AdvHwSerial && rxPin == 3 && txPin == 1) {
            log = F("NEXTION075 : Using USB hardware serial");
            addLog(LOG_LEVEL_INFO, log);
            HwSerial = true;
            Settings.UseSerial = false;                 // Disable global Serial port.
            Settings.SerialLogLevel = 0;                // Disable logging on serial port.
            Settings.BaudRate = AdvHwBaud;              // Set BaudRate for Nextion.
            Serial.flush();
            Serial.begin(AdvHwBaud);
        }
        else {
            log = F("NEXTION075 : Using software serial");
            addLog(LOG_LEVEL_INFO, log);
            HwSerial = false;
            if (SoftSerial == NULL) {
                SoftSerial = new ESPeasySoftwareSerial(rxPin, txPin);
            } 
            SoftSerial->begin(9600);
            SoftSerial->flush();
        }
    }
    else {
    }
      success = true;
      break;
    }


    case PLUGIN_READ: {    // Get Plugin's optional command-text strings. Special RSSIBAR bargraph keyword is supported.
        char deviceTemplate[Nlines][64];
        int RssiIndex;
        String newString;
        String tmpString;
        String UcTmpString;
        
        LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));

        for (byte x = 0; x < Nlines; x++) {
          tmpString = deviceTemplate[x];
          if (tmpString.length()) {
            UcTmpString = deviceTemplate[x];
            UcTmpString.toUpperCase();
            RssiIndex = UcTmpString.indexOf(F("RSSIBAR"));  // RSSI bargraph Keyword found, wifi value in dBm.
            if(RssiIndex >= 0) {
              int barVal;
              newString = tmpString.substring(0, RssiIndex);
              int nbars = WiFi.RSSI();
              if (nbars < -100 || nbars >= 0)
                 barVal=0;
              else if (nbars >= -100 && nbars < -95)
                 barVal=5;
              else if (nbars >= -95 && nbars < -90)
                 barVal=10;
              else if (nbars >= -90 && nbars < -85)
                 barVal=20;
              else if (nbars >= -85 && nbars < -80)
                 barVal=30;
              else if (nbars >= -80 && nbars < -75)
                 barVal=45;
              else if (nbars >= -75 && nbars < -70)
                 barVal=60;
              else if (nbars >= -70 && nbars < -65)
                 barVal=70;
              else if (nbars >= -65 && nbars < -55)
                 barVal=80;
              else if (nbars >= -55 && nbars < -50)
                 barVal=90;
              else if (nbars >= -50)
                 barVal=100;

              newString += String(barVal,DEC);
            }
            else {
              newString = parseTemplate(tmpString, 0);
            }

            sendCommand(newString.c_str(), HwSerial);
          }
        }

        success = true;
        break;
    }


    case PLUGIN_WRITE: {
        String tmpString = string;
        int argIndex = tmpString.indexOf(',');
        if (argIndex) tmpString = tmpString.substring(0, argIndex);

//      String log = F("TaskDeviceName : ");
//      log += ExtraTaskSettings.TaskDeviceName;
//      addLog(LOG_LEVEL_INFO, log);

        if (tmpString.equalsIgnoreCase(F("NEXTION"))) {
//      if (tmpString.equalsIgnoreCase(ExtraTaskSettings.TaskDeviceName)) { // Use Plugin Name as command ID name.
            argIndex = string.indexOf(',');
            tmpString = string.substring(argIndex + 1);
            sendCommand(tmpString.c_str(), HwSerial);

            String log = F("NEXTION075 : WRITE, ");
            log += F("Command is ");
            log += (tmpString.c_str());
            addLog(LOG_LEVEL_INFO, log);

            success = true;                             // Set true only if plugin found a command to execute.
        }
        break;
    }


    case PLUGIN_EXIT: {
      if (SoftSerial) {
        delete SoftSerial;
        SoftSerial=NULL;
      }

      if(HwSerial) {
        HwSerial = false;
        Settings.UseSerial		= DEFAULT_USE_SERIAL;
        Settings.BaudRate		= DEFAULT_SERIAL_BAUD;
        Serial.flush();
        Serial.begin(DEFAULT_SERIAL_BAUD);              // Restart Serial Logging with default baud.
      }
      break;
    }


    case PLUGIN_ONCE_A_SECOND: {
        success = true;
        break;
    }

    
    case PLUGIN_TEN_PER_SECOND: {
      uint16_t i;
      uint8_t c;
      uint8_t charCount;
      String log;
      String Vidx;
      String Nvalue;
      String Svalue;
      String Nswitch;
      char __buffer[RXBUFFSZ+1];

      if(HwSerial) charCount = Serial.available();      // Prime the Hardware Serial engine.
      else charCount = SoftSerial->available();         // Prime the Soft Serial engine.

      while (charCount) {                               // This is the serial engine. It processes the serial Rx stream.
        if(HwSerial) c = Serial.read();
        else c = SoftSerial->read();

        if (c == 0x65) {
          if (charCount < 6) delay((5/(AdvHwBaud/9600))+1); // Let's wait for a few more chars to arrive.

          if (HwSerial) charCount = Serial.available();
          else charCount = SoftSerial->available();
          if (charCount >= 6) {
            __buffer[0] = c;
            for (i = 1; i < 7; i++) {
                if(HwSerial) __buffer[i] = Serial.read();
                else __buffer[i] = SoftSerial->read();
            }

            __buffer[i] = 0x00;

            if (0xFF == __buffer[4] && 0xFF == __buffer[5] && 0xFF == __buffer[6]) {
              UserVar[event->BaseVarIndex] = (__buffer[1] * 256) + __buffer[2] + TOUCH_BASE;
              UserVar[event->BaseVarIndex + 1] = __buffer[3];
              log = F("NEXTION075 : code: ");
              log += __buffer[1];
              log += ",";
              log += __buffer[2];
              log += ",";
              log += __buffer[3];
              addLog(LOG_LEVEL_INFO, log);

              sendData(event);
            }
          }
        } 
        else {
          if (c == '|') {
            __buffer[0] = c;

            if (charCount < 8) delay((9/(AdvHwBaud/9600))+1); // Let's wait for more chars to arrive.
            else delay((3/(AdvHwBaud/9600))+1);               // Short wait for tardy chars.
            if (HwSerial) charCount = Serial.available();
            else charCount = SoftSerial->available();

            if(HwSerial) {
                i = 1;            
                while (Serial.available() > 0 && i<RXBUFFSZ) {  // Copy global serial buffer to local buffer.
                  __buffer[i] = Serial.read();
                  if (__buffer[i]==0x0a || __buffer[i]==0x0d) break;
                  i++;
                }
            }
            else {
                i = 1;            
                while (SoftSerial->available() > 0 && i<RXBUFFSZ) {  // Copy global serial buffer to local buffer.
                  __buffer[i] = SoftSerial->read();
                  if (__buffer[i]==0x0a || __buffer[i]==0x0d) break;
                  i++;
                }
            }

            __buffer[i] = 0x00;
            
            String tmpString = __buffer;
            log = F("NEXTION075 : code: ");
            log += tmpString;
            addLog(LOG_LEVEL_INFO, log);

            int argIndex = tmpString.indexOf(F(",i"));
            int argEnd = tmpString.indexOf(',', argIndex + 1);
            if (argIndex) Vidx = tmpString.substring(argIndex + 2,argEnd);

            boolean GotPipeCmd = false;
            switch (__buffer[1]){
              case 'u':
                GotPipeCmd = true;
                argIndex = argEnd;
                argEnd = tmpString.indexOf(',',argIndex + 1);
                if (argIndex) Nvalue = tmpString.substring(argIndex + 2,argEnd);
                argIndex = argEnd;
                argEnd = tmpString.indexOf(0x0a);
                if (argIndex) Svalue = tmpString.substring(argIndex + 2,argEnd);
                break;
              case 's':
                GotPipeCmd = true;
                argIndex = argEnd;
                argEnd = tmpString.indexOf(0x0a);
                if (argIndex) Nvalue = tmpString.substring(argIndex + 2,argEnd);
                if (Nvalue == F("On")) Svalue='1';
                if (Nvalue == F("Off")) Svalue='0';
                break;
            }

            if (GotPipeCmd) {
                UserVar[event->BaseVarIndex] = Vidx.toFloat();
                UserVar[event->BaseVarIndex+1] = Svalue.toFloat();
                sendData(event);
                log = F("NEXTION075 : Pipe Command Sent: ");
                log += __buffer;
                log += UserVar[event->BaseVarIndex];
            }
            else {
                log = F("NEXTION075 : Unknown Pipe Command, skipped");
            }
            addLog(LOG_LEVEL_INFO, log);
          }
        }
        if(HwSerial) charCount = Serial.available();
        else charCount = SoftSerial->available();
      }

      success = true;
      break;
    }
  }
  return success;
}


void sendCommand(const char *cmd, boolean SerialHW) 
{
    if(SerialHW) {
        Serial.print(cmd);
        Serial.write(0xff);
        Serial.write(0xff);
        Serial.write(0xff);
    }
    else {
        SoftSerial->print(cmd);
        SoftSerial->write(0xff);
        SoftSerial->write(0xff);
        SoftSerial->write(0xff);
    }
}

#endif // USES_P075

TD-er
Normal user
Posts: 838
Joined: 01 Sep 2017, 22:13
Location: the Netherlands
Contact:

Re: Nextion display plugin

#270 Post by TD-er » 14 Jul 2018, 08:57

You could store a command (originated from a rule for example) sent to the Nextion and process it later in the Nextion calls itself.
That would not interrupt/corrupt the data flow between Nextion and the ESP.

Also I see a lot of code duplication due to the fact you're experimenting with the HW serial.
I guess we should move this kind of code into the "ESPeasySoftwareSerial" code (and rename it of course) to prevent errors and make sure no other writer of plugins will have this kind of code-duplication in his or her code.

Then any plugin could switch to using hardware serial and also the check to have only one using it would be done there.

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest