Attention Nextion Users!

I've spent the last several days tearing my hair out over Nextion problems. I'm using the Nextion library, which I'm convinced was written by someone who had no idea what he was doing. What I found was my application was FREQUENTLY simply never seeing button events. It was not unusual for 30-50% of the events to simply go missing.

I finally wrote a test program to just exercise the interface, and found the display itself worked perfectly, but the library was randomly throwing away messages. So, I looked at how the library was parsing and processing messages, and it was a MESS!

nexLoop would read a single character, then delay 10 mSec, then check if there were at least 6 more waiting. If not, it would simply toss that one character, and return. If there were 6 or more characters, it would read the first 6. If the 7 character this read were a valid message, it would process it. If not it would toss the whole thing! This created several (bloody obvious!) problems:

  1. EVERY time you call nexLoop, it WASTES 10 mSec if there is even a single character waiting.
  2. If an ENTIRE message was not received during those 10 mSec, it would throw away the first character, which MIGHT be the first character of a valid message. This GUARANTEES the rest of that message WILL be discarded.

Even worse, EVERY time you call sendCommand (which is called by ANY set method that sends a message to the Nextion), it FLUSHES the receive pipe! This randomly discards even more data.

I don't doubt this all works fine, IF you NEVER use events, but otherwise, you are screwed, and will NEVER get events reliably.

So, I re-wrote several key sections of code. Now, I have a separate function, parseRx, that reads and parses the receive pipe, and places events and response messages into their own, separate FIFOs. This is the ONLY place where the Serial port is ever read. nexLoop and other functions now call two new functions, getEvent() or getResp() to get the next event, or the next response from the FIFOs.

This has COMPLETELY cured the problems I was having, and GREATLY improved performance. I have not seen a single missed event, the the whole application is MUCH more responsive.

There are two remaining bugs I have NOT fixed, which are related. recvRetNumber and recvRetString, which are used when you use numeric and string "getters", are broken, as I see no obvious way to deal with them given how stupid the Nextion protocol is. Right now, I don't need those, so it's not hurting me. If I get bored, I'll see if I can make them work again.

This is with the v0.9.0 library, which is, AFAICT, the latest version. But I fail to understand how anyone could use it as-is for anything but the simplest possible applications.

Regards,
Ray L.

I have some limited experience with a Nextion display: I built (or better said am still building) an RDS radio using a 2.4 inch Nextion and an Si4703 radio module.
It is a very simple application: On/Off switch; Volume up/down with a progress bar to indicate the setting, Channel up/down button and number block to display the selected channel and a text display area for a scrolling RDS message.
I used a very simple philosophy and did not use the Nextion C++ library at all. I had to invent my own strings to be sent from the display when a widget (e.g. volume_up was touched. When the application starts, previous used values are obtained from the Arduino eeprom (say last channel used) and sent to the display. Best is probably to have the minimum logic in the display and move, where possible, the complexity to the sketch.

For example, behind the Nextion Channel Down widget is:

va1.val=n0.val-1
if(va1.val>=1)
{
  n0.val=va1.val
}else
{
  n0.val=1
}
prints "_n0__",5
prints n0.val,1

where va1 is a temporary variable, n0 is the name of the channel number display widget.

In the sketch, I have:

SoftwareSerial Nextion(6,7) ; // rx, tx
. . .
// send channel to Nextion in Setup
chanCycle = 0 ;
Nextion.print("n0.val=") ;
Nextion.print(chanCycle+1 ) ; // 1..
Nextion.write(0xff);Nextion.write(0xff);Nextion.write(0xff);
. . .
// Nextion has send data (which is now in nextionBuffer) so handle it 
. . .
if (strncmp(nextionBuffer, "_n0__",5) == 0) {
  Serial.print("n0 channel ") ;
  Serial.println( nextionBuffer[5], DEC ) ;
  chanCycle = nextionBuffer[5] - 1 ;    // 0..8
}
. . .

This is all still work in progress. My main problem was finding decent looking graphics which I could use to make up the buttons etc. My efforts using, I seem to remember Visio, look all washed out. The development environment incidentally reminds me a bit of Lotus Notes which I had to use many years ago. There, if you managed to get something to work, it worked only under the exact circumstances under which it was tested. Even the slightest change would cause all sorts of rule exceptions to kick in and render the thing invalid.

Lotus Notes! EEEEEEEWWWWWWWWW!!!!!! That's something I haven't had to think about in a loooooong time!

The Nextion library is, overall, not bad, but the serial handling is simply abominable. Now that I've fixed all that, it is all working perfectly. I also fixed the other two functions (for receiving strings and numbers), so everything is now in good shape.

Putting the GUI "smarts" in the display is not a bad idea, but they could've done a better job of in several areas. In fact, design-wise, the hardware implementation SHOULD be completely de-coupled from the software. I can do development on a 3" display, then simply plug in a 7" display, with a completely different layout, and it all works perfectly, with NO changes to the software. That is as it should be.

Among the worst, bonehead things about the GUI designer: the hard-coded component IDs, which can ALL change at random. If you delete a single component, ALL of them can get re-numbered, which means changing your source code, since all the component constructors require the ID number as an argument. Stupid! The numbers should NEVER change.

There are also things you can do in the GUI editor that seem to irreparably whack the HMI file. This has happened to me several times. Something goes sideways, and one or more components will start to mis-behave. What I've seen most often is buttons which no longer send valid event messages. They are typically missing one or more bytes! If you then delete the offending component, re-create it, ALL the components get re-numbered, and whichever one(s) gets the old ID of the deleted component(s) will then start sending corrupted event messages. The only solution I've found is to re-build the entire GUI from scratch, in a new file. That sucks....

Regards,
Ray L.