Nextion display plugin

Moderators: grovkillen, Stuntteam, TD-er

Post Reply
Message
Author
User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#251 Post by ThomasB » 10 Jul 2018, 02:24

@BertB, @TD-er:
Thanks for the feedback. It would be great if you merged the revised Nextion Plug-in with the main branch (after a couple users try it out).

During validation I discovered that the 0x65 Touch Event code didn't work (broken in the original Nextion plugin release). I don't use it but no doubt others will want it. So it's working now.

Touch Events are the code that is sent when you enable the "Send Component ID" on a Nextion item. For details to 0x65 (ascii 'e') please see its reference here:
https://nextion.itead.cc/resources/docu ... ction-set/

I refactored the touch event code so that it creates an idx starting at 500. This reserves the first 499 codes for general purpose trigger states. I retained the original concept of packing the three values (page number, component ID, and touch state) into the bindings two event bytes (idx and value).

Integer math is used to unpack the idx value, pseudo coded follows.
b = Nextion idx - 500
Page Number = b / 256
Component ID = b modulo 256

Touch state = Nextion value (1=press event, 0 = release event)

Example: Touch event idx = 1527, event value = 1
(1527 - 500) / 256 = Page 4
(1527 - 500) modulo 256 = Component ID 3
Result: Component Page 4, Component ID 3, Press Event

After installing the PNP buffer transistor I discovered that sometimes boot would hang (on both hardware reset and web reset). Perhaps once every 50 boots the board would hang. The issue can be resolved by adding two 1/8W resistors to the PNP transistor. BTW, the PNP can be any general purpose type, such as PN2907 or 2N3906. See revised schematic image.
NextionHwSerialPinout1.jpg
NextionHwSerialPinout1.jpg (52.56 KiB) Viewed 122443 times
Because of today's fixes I need to re-validate the code again. So I'll need a bit more time.

- Thomas

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#252 Post by ThomasB » 10 Jul 2018, 21:07

Attached is the Nextion Plugin revisions dated July-10-2018. There will probably be some more minor edits, but it's time to let others try it out.

There were a lot of code changes, but the plugin stays true to the original; It supports the |u, |s, 0x65 commands. The rssi easter egg is still available too (but has been renamed to rssibar).

With hardware serial I have not experienced a single communication problem (100% data reliability). Furthermore, hardware serial would reliably support faster baud rates (softserial would fail). Faster data would be desirable on an app that transferred waveforms. But I didn't add a baud rate selector since I don't know if there were any ESPEz Nextion users that would care. For me, 9600 baud is fine. Any baud comments?

- Thomas

Code: Select all

//#######################################################################################################
//#######################################################################################################
//################################### Plugin 075: Nextion <info@sensorio.cz>  ###########################
//###################################   Created on the work of  majklovec     ###########################
//###################################    Revisions by BertB and ThomasB       ########################### 
//###################################    Last Revision: July-10-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]"
//#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.

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

// *****************************************************************************************************
// Functions start here
// *****************************************************************************************************

boolean Plugin_075(byte function, struct EventStruct *event, String &string) {
  static boolean HwSerial = false;
  static boolean AdvHwSerial = false;  
  boolean success = false;
  
  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_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(6);                  // 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("Nextion : 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(10);               // Let's wait for more chars to arrive.
            else delay(4);                              // 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("Nextion : 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);
            
            switch (__buffer[1]){
              case 'u':
                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':
                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;
            }

            UserVar[event->BaseVarIndex] = Vidx.toFloat();
            UserVar[event->BaseVarIndex+1] = Svalue.toFloat();

            log = F("Nextion : send command: ");
            log += __buffer;
            log += UserVar[event->BaseVarIndex];
            addLog(LOG_LEVEL_INFO, log);
            
            sendData(event);
          }
        }
        if(HwSerial) charCount = Serial.available();
        else charCount = SoftSerial->available();
      }

      success = true;
      break;
    }
    
    case PLUGIN_ONCE_A_SECOND: {
        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;
        }

        SaveCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
        Settings.TaskDevicePluginConfig[event->TaskIndex][0] = isFormItemChecked(F("AdvHwSerial"));
 
        success = true;
        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.
      }

      char deviceTemplate[Nlines][64];
      LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));

      addFormSeparator(2);
      addFormSubHeader(F("Enhanced Serial Communication"));
      addFormCheckBox(F("Use Hardware Serial"), F("AdvHwSerial"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
//    addRowLabel(F("Hardware Serial Notes:"));
      addFormNote(F("Un-check box for Soft Serial communication (low performance mode)."));
      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("The Serial Log file MUST be disabled in Tools->Advanced->Serial Port."));
      addFormSubHeader(F("")); // Blank line, vertical space.

      addFormHeader(F("Nextion Command-Text Strings (Optional)"));
//    addFormSubHeader(F("Nextion Text Strings (Optional pre-defined messages)"));
      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_INIT: {

      AdvHwSerial = Settings.TaskDevicePluginConfig[event->TaskIndex][0];

      if (Settings.TaskDevicePin1[event->TaskIndex] != -1) {
        rxPin = Settings.TaskDevicePin1[event->TaskIndex];
      }
      if (Settings.TaskDevicePin2[event->TaskIndex] != -1) {
        txPin = Settings.TaskDevicePin2[event->TaskIndex];
      }
        
      String log = F("NEXTION075 : serial pin config RX:");
      log += rxPin;
      log += F(", TX:");
      log += txPin;
      addLog(LOG_LEVEL_INFO, log);

      if (SoftSerial != NULL) { 
        delete SoftSerial;
        SoftSerial = NULL;
      }
      
      if(HwSerial == true) {
        HwSerial = false;
        Serial.flush();
        Serial.end();       // Close current serial port.
      }

      // 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;
        Serial.end();       // Close current serial port.
        Serial.begin(9600);
        Serial.swap();
        Serial.flush();

      }
      // Hardware serial is RX on 3 and TX on 1. USB developer serial mode.
      else if(AdvHwSerial && rxPin == 3 && txPin == 1)
      {
        log = F("NEXTION075 : Using standard hardware serial");
        addLog(LOG_LEVEL_INFO, log);
        HwSerial = true;
        Serial.end();       // Close current serial port.
        Serial.begin(9600);
        Serial.flush();
      }
      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();
      }

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

          if(HwSerial)
          {
            HwSerial = false;
            Serial.flush();
            Serial.end();
          }
          success = true;
          break;
      }

    case PLUGIN_READ: {                         // Get Plugin's optional command-text strings. Special rssi/RSSI 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 signal rescaled 0-100.
            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);
      if (tmpString.equalsIgnoreCase(F("NEXTION"))) {
        argIndex = string.indexOf(',');
        tmpString = string.substring(argIndex + 1);

        sendCommand(tmpString.c_str(), HwSerial);

        if (txPin != 1 && txPin !=15) {  // If Serial0 port is available then send entry to Log.
            Serial.println(tmpString);
        }
        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
Last edited by ThomasB on 10 Jul 2018, 22:12, edited 2 times in total.

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

Re: Nextion display plugin

#253 Post by BertB » 10 Jul 2018, 21:30

@ThomasB
I think you did a great job and I am eager to test your modifications.
I too had problems with the original 65 tough events and had to go back to very first implementation to get it working again.

In the documentation, I read that the GPIO15 port uses a pull up resistor to output a logic high level. I hope your 2k2 resistor to ground does not spoil that.

So, that is it for now. It is testing time :-)

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#254 Post by ThomasB » 10 Jul 2018, 21:41

BertB wrote: 10 Jul 2018, 21:30 @ThomasB
In the documentation, I read that the GPIO15 port uses a pull up resistor to output a logic high level. I hope your 2k2 resistor to ground does not spoil that.
Thanks for that information. Fortunately my o-scope shows that GPIO15 can still swing rail-to-rail with the resistor installed. So we are safe.
- Thomas

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#255 Post by ThomasB » 10 Jul 2018, 22:09

A correction was made to the posted code. Line 372 has a rssi name tweak, changed to:
// Old Code:
RssiIndex = UcTmpString.indexOf(F("RSSI")); // RSSI Keyword found

// New Code:
RssiIndex = UcTmpString.indexOf(F("RSSIBAR")); // RSSI bargraph Keyword found, wifi signal rescaled 0-100.
- Thomas
Last edited by ThomasB on 11 Jul 2018, 05:31, edited 3 times in total.

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#256 Post by ThomasB » 11 Jul 2018, 02:23

Rather than regret not doing it, I added the Baud Rate drop-down for hardware serial. The Nextion display supports baud rates 2400, 4800, 9600, 19200, 38400, 57600, and 115200.
nextion2.jpg
nextion2.jpg (72.49 KiB) Viewed 122383 times
The baud rate function has been tested with the Nextion Editor (via user MCU Input). I'll do more testing (with a Nextion Display) in a couple days. Also, I'll hold-off posting any more code to allow some feedback on today's release.

- Thomas

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#257 Post by ThomasB » 11 Jul 2018, 05:33

I just discovered that the ESP8266 will be corrupted if the Nextion plugin is deleted. It requires a full flash reset and re-installation. So until I figure out what is going on I suggest not using the new code.

- Thomas

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

Re: Nextion display plugin

#258 Post by BertB » 11 Jul 2018, 12:20

I am using you prepre version and removed the plugin on two ESP's without any problem.
I even could put them back in without a problem.

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

Re: Nextion display plugin

#259 Post by BertB » 11 Jul 2018, 13:17

I have problems too.
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 think it would be nice to put a undo serial.swap statement in the factory reset routine (the one activated with shorting Rx and Tx.
Simply unchecking the Serial Hardware box does not do the unswap job. Not even after a restart.

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#260 Post by ThomasB » 11 Jul 2018, 17:02

At this point I believe all these problems are due to the previously stored flash settings that are retained after a code reflash. The mapping of the user settings is different on the new code (several added values).

What I have done is reflash with Arduino's Erase Flash: All Flash Contents feature turned on. This erases everything, including WiFi and user settings. This is a pain because the ESP8266 must be restarted with WiFi AP and all settings re-entered. Do NOT restore using a previously saved ESPEz Settings file because that would cause the problem to return.

So a full erase-reflash has solved my crash problem caused by deleting the Nextion plug in.But I am still testing to see if this is a valid solution and not dumb luck.
Simply unchecking the Serial Hardware box does not do the unswap job. Not even after a restart.
The box is definitely working for me, so this seems to be a another side affect caused by the old settings' memory map.

- Thomas

User avatar
ThomasB
Normal user
Posts: 1064
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

User avatar
ThomasB
Normal user
Posts: 1064
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
Core team member
Posts: 3621
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]
Official shop: https://firstbyte.shop/
Sponsor ESP Easy, we need you :idea: :idea: :idea:

User avatar
ThomasB
Normal user
Posts: 1064
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
Core team member
Posts: 3621
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]
Official shop: https://firstbyte.shop/
Sponsor ESP Easy, we need you :idea: :idea: :idea:

BertB
Normal user
Posts: 1049
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..

User avatar
ThomasB
Normal user
Posts: 1064
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
Core team member
Posts: 3621
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]
Official shop: https://firstbyte.shop/
Sponsor ESP Easy, we need you :idea: :idea: :idea:

User avatar
ThomasB
Normal user
Posts: 1064
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
Core team member
Posts: 8643
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.

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

Re: Nextion display plugin

#271 Post by BertB » 14 Jul 2018, 09:17

Sounds like a good idea to me.

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#272 Post by ThomasB » 14 Jul 2018, 18:14

@TD-er: I was hoping to hear that there was a built-in method to postpone plugin Write events. Since that was wishful thinking, your suggestion (thanks!) is where I will go.

I looked through the ESP Easy code and can't find an existing string Queue routine to use. I don't want to re-invent the wheel so I prefer using a library function. There are a couple published queue handlers available, but that means it would have to be installed. Like this one:
https://playground.arduino.cc/Code/QueueList

Is adding another library frowned upon or is it a normal thing for the ESP Easy developers to do? Any guidance on this is appreciated.

Also, enhancing the ESPeasySoftwareSerial module to add functions to switch between hardware (both swap and USB) and soft serial would be fantastic. I'd be happy to contribute to the effort (not as a project leader, but can do some grunt work like testing/validation).

@BertB: Any chance you can try out the new V3 Nextion code and perform some validation? BTW, I found an odd issue with TaskDeviceName that required me to make some code changes shortly after I published it. So copy the V3 plugin's code again to ensure you have the revised V3.

- Thomas

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

Re: Nextion display plugin

#273 Post by BertB » 14 Jul 2018, 22:09

@ThomasB, I will do the testing.

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

Re: Nextion display plugin

#274 Post by BertB » 14 Jul 2018, 23:06

@ThomasB
After I installed your latest version V3, I started with using D7 and D8 as Rx and Tx, with the Use Hardware Serial left unchecked.
Initially this works fine, but for some reason, I get unintended events. It is as if press a switch (1274) on the Nextion, but I don't.

It happens once every minute and this is the serial log.
600472 : LoadFromFile: config.dat index: 4096 datasize: 472
600475 : LoadFromFile: config.dat index: 5120 datasize: 768
600537 : LoadFromFile: config.dat index: 6144 datasize: 472
600543 : LoadFromFile: config.dat index: 4096 datasize: 472
600572 : LoadFromFile: config.dat index: 6144 datasize: 472
600575 : LoadFromFile: config.dat index: 4096 datasize: 472
600603 : LoadFromFile: config.dat index: 6144 datasize: 472
600606 : LoadFromFile: config.dat index: 4096 datasize: 472
600637 : LoadFromFile: config.dat index: 6144 datasize: 472
600639 : LoadFromFile: config.dat index: 4096 datasize: 472
600676 : EVENT: E16Nextion#idx=1274.00
600684 : ACT : SendToHTTP xxx.xxx.xxx.xxx,8080,/json.htm?type=command&param=switchlight&idx=387&switchcmd=Toggle
600700 : Command: sendtohttp
600732 : HTTP/1.1 200 OK

600770 : EVENT: E16Nextion#idx=1274.00 Processing time:94 milliSeconds
600771 : EVENT: E16Nextion#value=0.00
600795 : EVENT: E16Nextion#value=0.00 Processing time:25 milliSeconds
600796 : LoadFromFile: config.dat index: 28672 datasize: 724
600814 : Domoticz: Sensortype: 5 idx: 1 values: 1274;0
600815 : MQTT : {"idx":1,"RSSI":3,"nvalue":0,"svalue":"1274;0"}
600818 : LoadFromFile: config.dat index: 29696 datasize: 724
600837 : HTTP : connecting to xxx.xxx.xxx.xxx:8080
600851 : Domoticz: Sensortype: 5 idx: 310 values: 1274;0
600881 : HTTP : Success
600888 : HTTP : closing connection
600985 : NEXTION075 : WRITE, Command is page3.b5.bco=48631
601472 : LoadFromFile: config.dat index: 6144 datasize: 472
603475 : EVENT: Clock#Time=Sat,23:02
603500 : EVENT: Clock#Time=Sat,23:02 Processing time:25 milliSeconds
603571 : LoopStats: shortestLoop: 46 longestLoop: 1137307 avgLoopDuration: 128.59 systemTimerDuration: 21.62 systemTimerCalls: 32 loopCounterMax: 652173 loopCounterLast: 230924 countFindPluginId: 0
603580 : PluginStats P_37_Generic - MQTT Import READ Count: 1 Avg/min/max 2541.00/2541/2541 usec
603589 : PluginStats P_37_Generic - MQTT Import ONCE_A_SECOND Count: 31 Avg/min/max 2177.32/2127/2541 usec
603599 : PluginStats P_37_Generic - MQTT Import TEN_PER_SECOND Count: 297 Avg/min/max 2225.59/2083/3868 usec
603609 : PluginStats P_37_Generic - MQTT Import WRITE Count: 2 Avg/min/max 2311.50/2094/2529 usec
603619 : PluginStats P_37_Generic - MQTT Import EVENT_OUT Count: 1 Avg/min/max 2813.00/2813/2813 usec
603629 : PluginStats P_37_Generic - MQTT Import SERIAL_IN Count: 1 Avg/min/max 2068.00/2068/2068 usec
603639 : PluginStats P_37_Generic - MQTT Import FIFTY_PER_SECOND Count: 1476 Avg/min/max 2147.14/2055/2684 usec
603647 : PluginStats P_71_Display - Nextion [TESTING_V3] READ Count: 1 Avg/min/max 200096.00/200096/200096 usec
603658 : PluginStats P_71_Display - Nextion [TESTING_V3] ONCE_A_SECOND Count: 31 Avg/min/max 34.45/26/47 usec
603668 : PluginStats P_71_Display - Nextion [TESTING_V3] TEN_PER_SECOND Count: 297 Avg/min/max 133.53/122/159 usec
603679 : PluginStats P_71_Display - Nextion [TESTING_V3] WRITE Count: 3 Avg/min/max 7632.00/134/22608 usec
603689 : PluginStats P_71_Display - Nextion [TESTING_V3] EVENT_OUT Count: 1 Avg/min/max 58.00/58/58 usec
603700 : PluginStats P_71_Display - Nextion [TESTING_V3] SERIAL_IN Count: 1 Avg/min/max 47.00/47/47 usec
603710 : PluginStats P_71_Display - Nextion [TESTING_V3] FIFTY_PER_SECOND Count: 1476 Avg/min/max 38.09/27/48 usec
603720 : Load File stats: Count: 13 Avg/min/max 4399.46/1332/19547 usec
603726 : Plugin call 50 p/s stats: Count: 1476 Avg/min/max 3122.74/2974/3819 usec
603734 : Plugin call 10 p/s stats: Count: 297 Avg/min/max 3275.19/3090/4900 usec
603741 : Plugin call 10 p/s U stats: Count: 297 Avg/min/max 3235.36/2997/3832 usec
603748 : Plugin call 1 p/s stats: Count: 31 Avg/min/max 18967.03/4096/425777 usec
603756 : checkSensors() stats: Count: 31 Avg/min/max 14398.42/547/422162 usec
603763 : sendData() stats: Count: 1 Avg/min/max 217326.00/217326/217326 usec
603771 : Compute formula stats: Count: 1 Avg/min/max 19.00/19/19 usec
603777 : WD : Uptime 10 ConnectFailures 0 FreeMem 14200

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#275 Post by ThomasB » 14 Jul 2018, 23:54

That's very interesting. Is it reliably happening every minute, or does the time vary?

On the bottom of the Nextion plugin web access page, directly above the Values names, is a Interval time scroll box. What is the value [sec] entered there?

- Thomas

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

Re: Nextion display plugin

#276 Post by BertB » 15 Jul 2018, 00:06

@ThomasB
It is 60 seconds, give or take a few.
The delay also is 60 sec.

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#277 Post by ThomasB » 15 Jul 2018, 00:31

Ok, then you are seeing expected behavior. The last received idx and value are stored. Then at each elapsed timer interval the idx and value are resent.

I assume that this is how other plugins' Interval function works. If not then I'll need to know what the expected behavior is so this plugin follows the ESPeasy standards.

The workaround? You can create a rule that sets the idx and value to 0 after your MQTT is sent. Then ignore 0 on future interval updates. In my home automation installation (Openhab) I have local rules that only trigger when the data changes. So repeated values are ignored.

- Thomas

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

Re: Nextion display plugin

#278 Post by BertB » 15 Jul 2018, 00:45

Two comments on that.
1 I cannot remember thuis happening with the original version.

2 In this case the event only triggers a rule. Idx will be id of the switch. Value is always 0.

I will test this in more detail tomorrow.

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#279 Post by ThomasB » 15 Jul 2018, 00:54

No code changes were made that would affect this behavior, so you'll find that the original does it too. But if this is wrong then we can fix it.
In this case the event only triggers a rule. Idx will be id of the switch. Value is always 0.
As an alternative you can set both to -1 (or any other number) after your MQTT. Just choose a number that does not normally occur so that you can ignore it.

Edit #1: My Nextion sends custom idx codes that range from 10 to 30. I don't sent Nextion Touch events, but have a rule for them in case I decide to do that in the future. So here's a ESPeasy rule example that sends a MQTT to my home controller, then masks the sent data (set to -1) so it can be ignored by the rule when the timer intervals occur:

Code: Select all

on NEXTION#idx do
  if [NEXTION#idx]>=10 and [NEXTION#idx]<=30
      Publish /%sysname%/NEXTION/idx,[NEXTION#idx]
  endif
  if [NEXTION#idx]>=500  // Touch Events
      Publish /%sysname%/NEXTION/idx,[NEXTION#idx]
      Publish /%sysname%/NEXTION/value,[NEXTION#value]
     NEXTION#value = -1
  endif
  NEXTION#idx = -1
endon


Edit #2
: I expect others will share your feelings about the repeating idx and value. So I have a solution; We can allow the user to disable the interval timer (set Interval to 0 secs). But let's talk about this some more after your validation is further along. All the needed changes can be folded into the next beta revision.

Thanks for doing the testing!

- Thomas

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

Re: Nextion display plugin

#280 Post by BertB » 15 Jul 2018, 12:50

ThomasB wrote: 15 Jul 2018, 00:54 No code changes were made that would affect this behavior, so you'll find that the original does it too. But if this is wrong then we can fix it.
I dare to disagree :-). I carried out some investigation and found out that your latest (7-13-2018) code has the flaw, whereas my latest modification (07082018) has not.
Just to be sure, below both versions. Off course, there is a lot of difference between them.

07082018 version:

Code: Select all

//#######################################################################################################
//################################### Plugin 075: Nextion <info@sensorio.cz>  ###########################
//################################### Created on the work of  majklovec       ###########################
//#######################################################################################################
#ifdef USES_P075

#define PLUGIN_075
#define PLUGIN_ID_075 75
//#define PLUGIN_NAME_075 "Display - Nextion [TESTING]"
#define PLUGIN_NAME_075 "Display - Nextion   [BERTB REV3]"
#define PLUGIN_VALUENAME1_075 "code"
#define PLUGIN_VALUENAME2_075 "value"
#define Nlines 12        // The number of different lines which can be displayed - each line is 64 chars max

boolean Plugin_075_init = false;

boolean Plugin_075(byte function, struct EventStruct *event, String &string) {
  boolean success = false;

  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));
      success = true;
      break;
    }

    case PLUGIN_GET_DEVICEGPIONAMES: {
      int rxPin = Settings.TaskDevicePin1[event->TaskIndex];
      int txPin = Settings.TaskDevicePin2[event->TaskIndex];
      
      if ((rxPin == 3 && txPin == 1) || (rxPin == 13 && txPin == 15)) {
        event->String1 = F("GPIO HW RX &larr;");
        event->String2 = F("GPIO HW TX &rarr;");
      }
      else {  // Soft Serial.
        event->String1 = F("GPIO SS RX &larr;");
        event->String2 = F("GPIO SS TX &rarr;");
      }
      break;
    }

    case PLUGIN_INIT: {

/*      LoadTaskSettings(event->TaskIndex);

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

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

      if (!nextion) {
        nextion = new ESPeasySoftwareSerial(Plugin_075_RXpin , Plugin_075_TXpin);
      }
*/
      Serial.begin(9600);
      Serial.flush();
      Serial.swap();

      Plugin_075_init = true;
      success = true;
      break;
    }

       
    case PLUGIN_TEN_PER_SECOND: {
      if(Plugin_075_init) {
        char __buffer[80];

        uint16_t i;
        uint8_t c;
        String Vidx;
        String Nvalue;
        String Svalue;
        String Nswitch;

        while (Serial.available() > 0) {
          delay(10);
          c = Serial.read();

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

              __buffer[i] = 0x00;

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

                addLog(LOG_LEVEL_INFO, log);
                sendData(event);
                
                success = true;
              }
              else success = false;
              
              return success;
            }
          }
          else if (c == '|') {
              i = 1;
              __buffer[0] = c;
              c=0;
              while (Serial.available() > 0) {
                __buffer[i] = Serial.read();
                if (__buffer[i]==0x0d) break;
                i++;
              }
              __buffer[i] = 0x00;

              String tmpString = __buffer;

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

              switch (__buffer[1]){

                case 'u':

                  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':

                  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;

                default:
                  success = false;
                  return success;
                  break;
                }

                UserVar[event->BaseVarIndex] = Vidx.toFloat();
                UserVar[event->BaseVarIndex+1] = Svalue.toFloat();

                String log = F("Nextion : send command: ");
                log += __buffer;
                log += UserVar[event->BaseVarIndex];
                addLog(LOG_LEVEL_INFO, log);
                sendData(event);

                ExecuteCommand(VALUE_SOURCE_SYSTEM, __buffer);

                success = true;
              }
              else success = false;
            }
          }
          break;
      }

    case PLUGIN_ONCE_A_SECOND: {
        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;

//          strncpy(deviceTemplate[varNr], WebServer.arg(argName).c_str(), sizeof(deviceTemplate[varNr]));
        }

        SaveCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));

      success = true;
      break;
    }

    case PLUGIN_WEBFORM_LOAD: {
      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_EXIT:
      {
          if (nextion)
          {
            delete nextion;
            nextion=NULL;
          }
          break;
      }
*/
    case PLUGIN_READ: {
        char deviceTemplate[Nlines][64];
        LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
        String newString;

        for (byte x = 0; x < Nlines; x++) {
          String tmpString = deviceTemplate[x];
          if (tmpString.length())
          {
            int rssiIndex = tmpString.indexOf(F("rssi"));
            if(rssiIndex >= 0)
            {
              int barVal;
              newString = tmpString.substring(0, rssiIndex);
              int nbars = WiFi.RSSI();
              if (nbars < -100)
                 barVal=0;
              else if (nbars >= -100 and nbars < -90)
                 barVal=20;
              else if (nbars >= -90 and nbars < -80)
                 barVal=40;
              else if (nbars >= -80 and nbars < -70)
                 barVal=60;
              else if (nbars >= -70 and nbars < -60)
                 barVal=80;
              else if (nbars >= -60)
                 barVal=100;

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

            sendCommand(newString.c_str());
          }
        }

        success = false;
        break;
      }


    case PLUGIN_WRITE: {
      String tmpString = string;
      int argIndex = tmpString.indexOf(',');
      if (argIndex)
        tmpString = tmpString.substring(0, argIndex);
      if (tmpString.equalsIgnoreCase(F("NEXTION"))) {
        argIndex = string.indexOf(',');
        tmpString = string.substring(argIndex + 1);

        sendCommand(tmpString.c_str());

//        Serial.println(tmpString);
        success = true;
      }
      break;
    }
  }
  return success;
}


void sendCommand(const char *cmd) {
  Serial.print(cmd);
  Serial.write(0xff);
  Serial.write(0xff);
  Serial.write(0xff);
}

#endif // USES_P075
07132018 version:

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
Thanks for doing the testing!
No problem. It is my baby too :-)

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

Re: Nextion display plugin

#281 Post by BertB » 15 Jul 2018, 13:12

I use a slightly modified version of your suggested work around, but it seems that idx and value won't modify.

Code: Select all

on E16NEXTION#idx do
  if [E16NEXTION#idx]>=1274  // Touch Events
      SendToHTTP xxx.xxx.xxx.xxx,8080,/json.htm?type=command&param=switchlight&idx=387&switchcmd=Toggle
      E16NEXTION#value = -1
  endif
  E16NEXTION#idx = -1
endon
This is the log:

Code: Select all

1865069 : EVENT: E16Nextion#idx=1274.00
1865078 : [if 1274>=1274]=true
1865080 : ACT  : SendToHTTP xxx.xxx.xxx.xxx,8080,/json.htm?type=command&param=switchlight&idx=387&switchcmd=Toggle
1865097 : Command: sendtohttp
1865122 : HTTP/1.1 200 OK

1865140 : ACT  : E16NEXTION#value = -1
1865154 : Command: e16nextion#value
1865155 : Command unknown
1865160 : ACT  : E16NEXTION#idx = -1
1865173 : Command: e16nextion#idx
1865173 : Command unknown
1865195 : EVENT: E16Nextion#idx=1274.00 Processing time:126 milliSeconds
1865196 : EVENT: E16Nextion#value=0.00
1865223 : EVENT: E16Nextion#value=0.00 Processing time:27 milliSeconds
1865225 : LoadFromFile: config.dat index: 28672 datasize: 724

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#282 Post by ThomasB » 15 Jul 2018, 19:30

@BertB: Thanks for hanging in there! This morning I recompiled with the original release (before hard serial). It has the same interval behavior as the latest V3 beta.

To test your version what method are you using to review the ESP log? The web interface's log has never worked correctly for me, so I need to come up with an alternate method that avoids edits to my home automation system.

Your rule workaround's log looks like it should work because idx has been set to -1. I say that because it matches the log I see on mine.

Code: Select all

19844 : EVENT: NEXTION#idx=20.00
19878 : ACT  : Publish /ESPEZ_Laundry/NEXTION/idx,20
19889 : Command: publish
19923 : ACT  : NEXTION#idx = -1
19934 : Command: nextion#idx
19946 : Command unknown
19981 : EVENT: NEXTION#value=0.00
20096 : Command: |s
20097 : Command unknown
After this there are no future log entries of the NEXTION since idx=-1 and the rule ignores it.

There's some interesting things going on here. In the meantime, do your best to continue with the validation so all the issues can be identified.

Lastly, if you are using the Arduino IDE, what compiler version is it? I would be good for me to know what others are using.

- Thomas

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#283 Post by ThomasB » 15 Jul 2018, 19:53

@BertB: Is the assigned name of your plugin NEXTION or is it E16NEXTION? The reason I ask is that there's a ESP bug that requires the user assigned name for this plugin to always be set to NEXTION or some things will not work correctly. So please change the Plugin name to "NEXTION" plus update the rule file to match this name.

- Thomas

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

Re: Nextion display plugin

#284 Post by BertB » 15 Jul 2018, 20:41

ThomasB wrote: 15 Jul 2018, 19:53 @BertB: Is the assigned name of your plugin NEXTION or is it E16NEXTION? The reason I ask is that there's a ESP bug that requires the user assigned name for this plugin to always be set to NEXTION or some things will not work correctly. So please change the Plugin name to "NEXTION" plus update the rule file to match this name.

- Thomas
Okay ... did not know that. I named it E16Nextion.

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

Re: Nextion display plugin

#285 Post by BertB » 15 Jul 2018, 20:48

ThomasB wrote: 15 Jul 2018, 19:30
To test your version what method are you using to review the ESP log? The web interface's log has never worked correctly for me, so I need to come up with an alternate method that avoids edits to my home automation system.
[/qoute]
I agree, the web log is not working correctly. Once the Serial.swap() has been executed, you are virtually blind for debug info.
On the other hand, the V3 version I tested, was with both softserial and hw serial.
There was no difference in 60 sec behaviour, but with softserial you have some proper debug info.

[qoute]
Your rule workaround's log looks like it should work because idx has been set to -1. I say that because it matches the log I see on mine.

Code: Select all

19844 : EVENT: NEXTION#idx=20.00
19878 : ACT  : Publish /ESPEZ_Laundry/NEXTION/idx,20
19889 : Command: publish
19923 : ACT  : NEXTION#idx = -1
19934 : Command: nextion#idx
19946 : Command unknown
19981 : EVENT: NEXTION#value=0.00
20096 : Command: |s
20097 : Command unknown
After this there are no future log entries of the NEXTION since idx=-1 and the rule ignores it.

[/qoute]
I only use the ids of Nextion objects. 60 sec thing was still hapening.
Lastly, if you are using the Arduino IDE, what compiler version is it? I would be good for me to know what others are using.

- Thomas
IDE 1.8.5 with 2.4.1

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

Re: Nextion display plugin

#286 Post by BertB » 15 Jul 2018, 21:14

I am running V3 again, changed E16Nextion to Nextion and no difference.
My garage light looks like a disco.

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

Re: Nextion display plugin

#287 Post by BertB » 15 Jul 2018, 21:27

I just used platformio to compile and upload the lot.
No change, 60sec interval still there

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#288 Post by ThomasB » 15 Jul 2018, 21:41

Thanks for all the info. At this point I don't have a solution that would retain the interval timer, but skip sending idx and value data. That's because the main purpose of the interval function is to periodically send these values. Even if we reset them to something else, they will still be sent at each interval.

Your observation that your Nextion version doesn't do it is a mystery to me. When the dust settles, maybe you can dig in deeper to determine how your code skips sending the data at each interval period.

But in the meantime, here is a workaround. Just set the interval to 0 [sec] and it will turn off the interval timer. This will allow you to continue the testing without the garage disco dance.

Code: Select all

//#######################################################################################################
//#######################################################################################################
//################################### Plugin 075: Nextion <info@sensorio.cz>  ###########################
//###################################   Created on the work of  majklovec     ###########################
//###################################    Revisions by BertB and ThomasB       ########################### 
//###################################    Last Revision: July-15-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 [TEST_V3.1]"
#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].TimerOptional = true;             // Allow user to disable interval function.
      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);
      }
      if( Settings.TaskDeviceTimer[event->TaskIndex]==0) {
        addFormNote(F("Interval Timer OFF: Nextion Lines and Values <b>NOT</b> scheduled for updates."));
      }
      else {
        addFormNote(F("Interval Timer On: Nextion Lines and Values scheduled for updates."));
      }


      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
- Thomas

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

Re: Nextion display plugin

#289 Post by BertB » 15 Jul 2018, 22:25

Thanks I will try it tomorrow.

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

Re: Nextion display plugin

#290 Post by BertB » 15 Jul 2018, 23:24

What I do not understand is this:
When I push a button, this causes serial data to flow to the serial port. This causes an event, where idx and value are being filled.
When this event occurs it triggers a rule.

Once every 60 seconds, idx and value are read and (in my case) send to a dummy device in Domoticz.
Why does this lead to another serial event and trigger the rule?

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#291 Post by ThomasB » 16 Jul 2018, 00:15

@BertB: At each timer interval the two "Values" data (idx and value) will be sent again. Without new data from the Nextion they default to the previous values.

This is the same as any other device that has defined Values and use a interval timer. For example, a Switch device will send the switch state at each interval. Even if the switch state has not been altered, the previous data will be sent again at the interval. That is the purpose of the interval function.

In your example the originating idx was a 1274 touch event. After the initial send, it is resent at the interval time. It is then processed by the rule file, which activates your light again. The "-1" workaround could fix this (because the rule would be ignored when idx is -1), but for some reason that trick is not working for you.

The new code will allow you turn off the interval timer and avoid the 60 second repeat. If there are alternate methods then we can incorporate them too.

- Thomas

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#292 Post by ThomasB » 16 Jul 2018, 04:16

I installed a syslog server on my NAS and can now send ESP log files to it. This allowed me to see what your code is doing. It has the same interval behavior as the original Nextion release and the latest V3 code.

Using your code here's the log output of event idx 21 and value 0. This log was captured several minutes after the Nextion sent the idx code 21 to the ESP. In this example the Nextion interval is 10 sec so the repeated data appears often. I also removed the -1 masking trick from the rule file so that the MQTT publish is seen too.

Code: Select all

18:39:33	EspEasy: EVENT: NEXTION#idx=21.00
18:39:33	EspEasy: WD   : Uptime 22 ConnectFailures 0 FreeMem 14384
18:39:33	EspEasy: LoopStats: shortestLoop: 49 longestLoop: 2083484 avgLoopDuration: 89.40 systemTimerDuration: 19.35 systemTimerCalls: 31 loopCounterMax: 612244 loopCounterLast: 328986 countFindPluginId: 0
18:39:23	EspEasy: EVENT: RSSI#signal=-75.00
18:39:23	EspEasy: SYS  : -75.00
18:39:23	EspEasy: EVENT: NEXTION#value=0.00
18:39:23	EspEasy: Command: publish
18:39:23	EspEasy: ACT  : Publish /ESPEZ_Laundry/NEXTION/idx,21
18:39:23	EspEasy: EVENT: NEXTION#idx=21.00
18:39:13	EspEasy: EVENT: NEXTION#value=0.00
18:39:13	EspEasy: Command: publish
18:39:13	EspEasy: ACT  : Publish /ESPEZ_Laundry/NEXTION/idx,21
18:39:13	EspEasy: EVENT: NEXTION#idx=21.00
18:39:03	EspEasy: EVENT: RSSI#signal=-76.00
18:39:03	EspEasy: SYS  : -76.00
18:39:03	EspEasy: EVENT: RUNTIME#days=0.01
18:39:03	EspEasy: SYS  : 21.00
18:39:03	EspEasy: EVENT: NEXTION#value=0.00
18:39:03	EspEasy: Command: publish
18:39:03	EspEasy: ACT  : Publish /ESPEZ_Laundry/NEXTION/idx,21
18:39:03	EspEasy: EVENT: NEXTION#idx=21.00
18:39:03	EspEasy: WD   : Uptime 21 ConnectFailures 0 FreeMem 14384
18:39:03	EspEasy: LoopStats: shortestLoop: 49 longestLoop: 2083484 avgLoopDuration: 88.74 systemTimerDuration: 20.94 systemTimerCalls: 31 loopCounterMax: 612244 loopCounterLast: 331381 countFindPluginId: 0
18:39:00	EspEasy: EVENT: Clock#Time=Sun,18:39
18:38:53	EspEasy: EVENT: NEXTION#value=0.00
18:38:53	EspEasy: Command: publish
18:38:53	EspEasy: ACT  : Publish /ESPEZ_Laundry/NEXTION/idx,21
18:38:53	EspEasy: EVENT: NEXTION#idx=21.00
18:38:43	EspEasy: EVENT: RSSI#signal=-77.00
18:38:43	EspEasy: SYS  : -77.00
18:38:43	EspEasy: EVENT: NEXTION#value=0.00
18:38:43	EspEasy: Command: publish
18:38:43	EspEasy: ACT  : Publish /ESPEZ_Laundry/NEXTION/idx,21
18:38:43	EspEasy: EVENT: NEXTION#idx=21.00
18:38:33	EspEasy: EVENT: NEXTION#value=0.00
18:38:33	EspEasy: Command: publish
18:38:33	EspEasy: ACT  : Publish /ESPEZ_Laundry/NEXTION/idx,21
18:38:33	EspEasy: EVENT: NEXTION#idx=21.00
18:38:33	EspEasy: WD   : Uptime 21 ConnectFailures 0 FreeMem 14384
18:38:33	EspEasy: LoopStats: shortestLoop: 49 longestLoop: 2083484 avgLoopDuration: 89.47 systemTimerDuration: 19.65 systemTimerCalls: 31 loopCounterMax: 612244 loopCounterLast: 328733 countFindPluginId: 0
18:38:23	EspEasy: EVENT: RSSI#signal=-77.00
18:38:23	EspEasy: SYS  : -77.00
18:38:23	EspEasy: EVENT: NEXTION#value=0.00
18:38:23	EspEasy: Command: publish
18:38:23	EspEasy: ACT  : Publish /ESPEZ_Laundry/NEXTION/idx,21
18:38:23	EspEasy: EVENT: NEXTION#idx=21.00
I don't use Nextion Touch events because I prefer a different numerical code for On and Off commands. This, along with my home automation's On Change rule, eliminates any worries of repeated data.

There may be a way to suppress the idx and val from the interval timer (and retain the Lines function), but that will require some research.

- Thomas

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

Re: Nextion display plugin

#293 Post by BertB » 16 Jul 2018, 06:59

ThomasB wrote: 16 Jul 2018, 00:15

In your example the originating idx was a 1274 touch event. After the initial send, it is resent at the interval time. It is then processed by the rule file, which activates your light again.
That is exactly my point. Why would a timer interval invoke a rule that should be event driven by the switch. In my case, the timer sends the values to a domoticz waste bin.

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

Re: Nextion display plugin

#294 Post by BertB » 16 Jul 2018, 07:03

ThomasB wrote: 16 Jul 2018, 04:16 I installed a syslog server on my NAS and can now send ESP log files to it. This allowed me to see what your code is doing. It has the same interval behavior as the original Nextion release and the latest V3 code.

So weird as on my wemos my latest code does not show the 60 sec on off behaviour. Tonite i will start from scrap..

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#295 Post by ThomasB » 16 Jul 2018, 07:51

That is exactly my point. Why would a timer interval invoke a rule that should be event driven by the switch. In my case, the timer sends the values to a domoticz waste bin.
I'm just the messenger, so don't shoot me. It's the behavior of the interval timer. It can be turned off now, so you should be good to go.
- Thomas

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

Re: Nextion display plugin

#296 Post by BertB » 16 Jul 2018, 14:10

ThomasB wrote: 16 Jul 2018, 07:51 I'm just the messenger, so don't shoot me.

- Thomas
Most certainly not. :-)

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

Re: Nextion display plugin

#297 Post by BertB » 16 Jul 2018, 23:48

So far, the plugin is running just fine.

User avatar
ThomasB
Normal user
Posts: 1064
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#298 Post by ThomasB » 17 Jul 2018, 02:19

@BertB: Thanks for checking it. Let me know if any other issues come up.

@Everyone: Would be great if there were others that could try it out. More feedback would be helpful.

I found a CustomTaskSettings byte storage mistake in the Nextion Plugin. But fixing it did not solve the crash/brick when the plugin is deleted and system rebooted. I see an Exception (28) in the logs right after the rule file tries to process a Nextion statement.

The workaround is to delete Nextion rules before deleting the plugin. If I don't do that then the recovery is to reflash with full memory reset. The problem comes and goes, depending on its mood.

The original Nextion plugin (without hardware serial) experiences the problem too. My gut feeling is that it has nothing to do with the Nextion Plugin.

- Thomas

User avatar
ManS-H
Normal user
Posts: 279
Joined: 27 Dec 2015, 11:26
Location: the Netherlands

Re: Nextion display plugin

#299 Post by ManS-H » 17 Jul 2018, 10:43

Hello,
I have a question about the Nextion display, maybe not the right place to ask but what version of the Nextion is most common for this plugin.
On the Itead site i see two versions, the Basic Model and the Enhanced Model.

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

Re: Nextion display plugin

#300 Post by BertB » 17 Jul 2018, 11:57

I only have tested and developed with the Basic model.

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 35 guests