Nextion display plugin

Moderators: grovkillen, Stuntteam, TD-er

Post Reply
Message
Author
r_255
Normal user
Posts: 32
Joined: 20 Nov 2015, 20:42

Re: Nextion display plugin

#201 Post by r_255 » 25 Jun 2018, 12:40

Thanks for clearifying,

Well i guess i most cases loosing your serial doesnt hurt anything. Debug and commands can be send thru the webinterface.

I agree on that its a pitty we cant have it working as intended within espeasy, as 90% of my esps run on it and it was my startpoint.
It would be sweet to simply make a rule and set the dim screen level based on the esp witty its lux levels.

I got my nextion running on a esp witty and changed the gpio's to the hardware serial as you can detach the usb to serial part leaving you a hardware rx and tx exposed. I did not try that with espeasy, as the rule engine in espeasy did not have enough space for my remote controller.

In the end i did decide to use node red as man in the middle, as my setup is kind of dynamic and i dont want to change my interface that much, and if i have to its a mather of changing a few options in node red. instead of using the nextion software, upload it thru sd etc. This way works for me and keeps things dynamic.

So basicly you can make buttons with labels and a id nummer, fill the labels dynamic from node red and do a action based on a button id catch.

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

Re: Nextion display plugin

#202 Post by BertB » 26 Jun 2018, 20:01

@ThomasB
I have an ESP8266 (WeMos) with an OLED, a switch, an MH-Z19CO2 device (serial interface) and a PMSx003 DUST sensor, also serial.
Both serial devices use SoftSerial and hardly ever miss data.

The Ser2Net device uses the hardware Rx and Tx. So, it shouldn't be too difficult to embed that option in the Nextion plugin.

I noticed that you have a switch in your device list. Is that to wake-up the OLED? You do not need to declare it seperately
Furthermore, I see two OLED displays. Dou you use both?

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

Re: Nextion display plugin

#203 Post by ThomasB » 26 Jun 2018, 20:42

@BertB

* Just curious, is your Wemos using 160MHz CPU clock or the default 80MHz?

* Thanks for pointing out that ser2net is using hardware UART. Too bad the existing Nextion Plugin does not support the UART as an optional implementation. If I get desperate I may take on the challenge, but so far my workaround is fine.

* The OLED devices are disabled. The project started with an OLED, but their small text is a problem for my wife's eyes. So OLED is abandoned and has been replaced with Nextion.

* Presently there are two "switch" devices. One is assigned to a HV optoisolator for sensing the Washing machine is running, the other goes to vibration detector on the dryer. But I'm changing the vibration detector to MPU6050 Accelerometer (higher sensitivity to detect the dryer spin). Just waiting for the sensor to arrive from the China supplier.

- Thomas

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

Re: Nextion display plugin

#204 Post by BertB » 26 Jun 2018, 21:02

@ThomasB
My WeMos runs on 80 MHz.

Perhaps TD-er can modify the plugin to use the hardware USART. I would give it a try myself, but for some reason, I cannot get useful compilations.

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

Re: Nextion display plugin

#205 Post by ThomasB » 26 Jun 2018, 21:29

Using the hardware UART would be the holy grail. :)

TD-er
Core team member
Posts: 1339
Joined: 01 Sep 2017, 22:13
Location: the Netherlands
Contact:

Re: Nextion display plugin

#206 Post by TD-er » 26 Jun 2018, 23:39

ThomasB wrote:
26 Jun 2018, 21:29
Using the hardware UART would be the holy grail. :)
And it isn't that hard to do.
Only problem is that you also have to make sure no other things make use of these pins.
So you have to disable serial logging and be able to disconnect the sensor when flashing when using uart0.
I know there are also pins designated to uart1, but I don't know if that's a hardware serial or not.

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

Re: Nextion display plugin

#207 Post by BertB » 26 Jun 2018, 23:57

TD-er wrote:
26 Jun 2018, 23:39
ThomasB wrote:
26 Jun 2018, 21:29
Using the hardware UART would be the holy grail. :)
And it isn't that hard to do.
Only problem is that you also have to make sure no other things make use of these pins.
So you have to disable serial logging and be able to disconnect the sensor when flashing when using uart0.
I know there are also pins designated to uart1, but I don't know if that's a hardware serial or not.
From the ESP8266 datasheet:
Data transfers to/from UART interfaces can be implemented via hardware. The data
transmission speed via UART interfaces reaches 115200 x 40 (4.5
Mbps).
UART0 can be used for communication. It supports fluid control. Since UART1 features
only data transmit signal (Tx), it is usually used for printing log.

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

Re: Nextion display plugin

#208 Post by ThomasB » 27 Jun 2018, 00:14

I agree, using hardware serial means disabling the debug and serial command processor. Then turn on the UART's Rx interrupt and point it to a Rx data buffer handler routine that Nextion can access. Seems easy, but "easy" coding is sometimes full of twists and turns.

There's only one full hardware UART in the ESP8266. But there's two sets of Rx & Tx pins. I understand that a pin swap register determines which pin pairs are routed to the UART. This pin swapping feature would be convenient for wiring the NEXTION display to the UART if someone enhances the Nextion plugin.

Edit1: "Since UART1 features only data transmit signal (Tx), it is usually used for printing log."
Too bad they skimped on the silicon. We need a Rx UART to fix this problem.

Edit2: Here's some useful information about UART2's Tx, along with the pin swapping features:
http://smallbits.marshall-tribe.net/blo ... quiet-uart

Not to be a broken record, but I have fixed my data corruption problem using the workaround explained earlier. But I would definitely switch to the hardware UART solution if someone does it without breaking the other functions provided by ESPEasy.

- Thomas

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

Re: Nextion display plugin

#209 Post by BertB » 27 Jun 2018, 10:10

As far as I know, debug info stays available via the web interface.

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

Re: Nextion display plugin

#210 Post by BertB » 27 Jun 2018, 16:11


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

Re: Nextion display plugin

#211 Post by ThomasB » 27 Jun 2018, 18:32

The ESP8266 UART features certainly have a lot of flexibility. But it's frustrating to find that the second UART is crippled (Tx only). Sure there are workarounds to this shortcoming, but two full UARTS would have been a more desirable implementation.

- Thomas

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

Re: Nextion display plugin

#212 Post by BertB » 27 Jun 2018, 20:14

Well, after doing some diging ... , a simple Serial.swap(); is enough to swap Rx and Tx to DPIO13 and GPIO15 respectively.
Serial

Serial object works much the same way as on a regular Arduino. Apart from hardware FIFO (128 bytes for TX and RX) HardwareSerial has additional 256-byte TX and RX buffers. Both transmit and receive is interrupt-driven. Write and read functions only block the sketch execution when the respective FIFO/buffers are full/empty.

Serial uses UART0, which is mapped to pins GPIO1 (TX) and GPIO3 (RX). Serial may be remapped to GPIO15 (TX) and GPIO13 (RX) by calling Serial.swap() after Serial.begin. Calling swap again maps UART0 back to GPIO1 and GPIO3.

Serial1 uses UART1, TX pin is GPIO2. UART1 can not be used to receive data because normally it's RX pin is occupied for flash chip connection. To use Serial1, call Serial1.begin(baudrate).

If Serial1 is not used and Serial is not swapped - TX for UART0 can be mapped to GPIO2 instead by calling Serial.set_tx(2) after Serial.begin or directly with Serial.begin(baud, config, mode, 2).

By default the diagnostic output from WiFi libraries is disabled when you call Serial.begin. To enable debug output again, call Serial.setDebugOutput(true). To redirect debug output to Serial1 instead, call Serial1.setDebugOutput(true).

You also need to use Serial.setDebugOutput(true) to enable output from printf() function.

Both Serial and Serial1 objects support 5, 6, 7, 8 data bits, odd (O), even (E), and no (N) parity, and 1 or 2 stop bits. To set the desired mode, call Serial.begin(baudrate, SERIAL_8N1), Serial.begin(baudrate, SERIAL_6E2), etc.
Source: http://esp8266.github.io/Arduino/versio ... rence.html

And this is what you see via the normal serial port during boot:
⸮U47865 :


INIT : Booting version: (custom) (ESP82xx Core 2_4_1, NONOS SDK 2.2.1(cfd48f3), LWIP: 2.0.3)
47865 : INIT : Warm boot #24 - Restart Reason: External System
47870 : FS : Mounting...
47895 : FS : Mount successful, used 76053 bytes of 957314
47909 : CRC : No program memory checksum found. Check output of crc2.py
47940 : CRC : SecuritySettings CRC ...OK
And this can still be seen on the web log:
948350: EVENT: E8DHT#Temperature=24.60
948356: EVENT: E8DHT#Humidity=52.90
948382: Domoticz: Sensortype: 2 idx: 312 values: 24.60;52.90;1
948446: WD : Uptime 15 ConnectFailures 0 FreeMem 16216
978446: WD : Uptime 16 ConnectFailures 0 FreeMem 16240
985324: EVENT: Clock#Time=Wed,20:26
1008446: WD : Uptime 16 ConnectFailures 0 FreeMem 15936
1008500: DHT : Temperature: 24.60
1008500: DHT : Humidity: 52.60
1008502: EVENT: E8DHT#Temperature=24.60
1008508: EVENT: E8DHT#Humidity=52.60
1008536: Domoticz: Sensortype: 2 idx: 312 values: 24.60;52.60;1
1019950: SaveToFile: config.dat index: 0 datasize: 1220
1020012: FILE : Saved config.dat
1038446: WD : Uptime 17 ConnectFailures 0 FreeMem 15864
1044476: EVENT: Clock#Time=Wed,20:27
1044482: EVENT: Clock#Time=Wed,20:27 Processing time:6 milliSeconds

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

Re: Nextion display plugin

#213 Post by ThomasB » 27 Jun 2018, 20:49

Hopefully you continue with your efforts and successfully get Nextion communication moved over to the hardware UART.

- Thomas

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

Re: Nextion display plugin

#214 Post by BertB » 28 Jun 2018, 14:51

I spent a number of hours on experimenting, reading and searching but.
There is an issue with Serial.swap() as it redirects TX to GPIO15.
At bootup of the ESP8266, GPIO has to be low and the Nextion pulls it high. :?

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

Re: Nextion display plugin

#215 Post by ThomasB » 28 Jun 2018, 16:39

I wish I could help with the UART code, but at this point all I can do is cheer you on.
- Thomas

User avatar
grovkillen
Core team member
Posts: 3140
Joined: 19 Jan 2017, 12:56
Location: Hudiksvall, Sweden
Contact:

Re: Nextion display plugin

#216 Post by grovkillen » 28 Jun 2018, 23:27

You could always try to lower the "message delay" found under Advanced settings (MQTT). Default is set to 1000mSec but I tend to always lower this to "100". But setting it to "0" will also work, could you please just try to set it to zero (0)? We are experimenting with this value to see what it actually does to the system and we suspect it to be making more harm then good (as in we need to fix whatever it is for in a better way).
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: 375
Joined: 17 Jun 2018, 20:41
Location: USA

Re: Nextion display plugin

#217 Post by ThomasB » 28 Jun 2018, 23:56

@grovkillen, I'm not sure if you are directing your comments to me. But to offer some feedback, I've already experimented with the MQTT interval. Currently MQTT it is 75mS. I had tried 0mS and other values, none helped solve my problem.

That was before I discovered that the problem was due to the interrupt latency. The issue became clear when I got out the o-scope and analyzed the RxD bit stream.

To summarize, the data corruption isn't with MQTT communication. Instead, it is due to the limitations of SoftSerial and its interrupt latency sensitive "bit-bang" data reads. I have posted a scope waveform that shows an example of too much latency and its impact on the affected serial data byte.

- Thomas
Last edited by ThomasB on 29 Jun 2018, 00:01, edited 1 time in total.

User avatar
grovkillen
Core team member
Posts: 3140
Joined: 19 Jan 2017, 12:56
Location: Hudiksvall, Sweden
Contact:

Re: Nextion display plugin

#218 Post by grovkillen » 29 Jun 2018, 00:00

Thanks Thomas, yes I was talking to you :)

And thanks for the feedback on the test of values, just to inform you and whoever reads this, the message delay is used by more things than just MQTT. We are experimenting with it right now to see where it impacts the performance.
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:

TD-er
Core team member
Posts: 1339
Joined: 01 Sep 2017, 22:13
Location: the Netherlands
Contact:

Re: Nextion display plugin

#219 Post by TD-er » 29 Jun 2018, 00:01

We (very) recently discovered this Message Delay setting to be stalling the normal loop execution.
This also means the "50/sec" and "10/sec" loop calls may not be services as often als the names suggest.

So it was just a suggestion to look into this.
If it is indeed interrupt related (or better, lack of interrupt), then it is indeed something that cannot be fixed by adjusting this delay.
Glad you already did test that.

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

Re: Nextion display plugin

#220 Post by ThomasB » 29 Jun 2018, 00:14

If the MQTT routines employ any service interrupts (or disable global interrupts) that take too much time then it would definitely impact software serial.

What I have observed is that typical latency into the SoftSerial read function is about 10uS, which is great. At 9600baud, I expect it would still work reliably with as much as 80uS. But randomly something is blocking the interrupt for a very long time (>135uS).

- Thomas

TD-er
Core team member
Posts: 1339
Joined: 01 Sep 2017, 22:13
Location: the Netherlands
Contact:

Re: Nextion display plugin

#221 Post by TD-er » 29 Jun 2018, 00:20

I just found out (as in this evening) that the Message Delay setting is causing the sendData function to stall for about this time.
That function is called from the once-per-second loop and the message delay is being used even when no MQTT is being used.

So I will definitely change how this affects performance.

Also the wifi has to be served every now and then and that may take some time.
You cannot call the yield function from within the interrupt handler in the Software Serial routine. But you could do a call to yield when parsing the data.
If it is handled more often, the time needed for handling the wifi connection is often less per call.

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

Re: Nextion display plugin

#222 Post by ThomasB » 29 Jun 2018, 00:45

I just found out (as in this evening) that the Message Delay setting is causing the sendData function to stall for about this time.
That is interesting to hear.
You cannot call the yield function from within the interrupt handler in the Software Serial routine. But you could do a call to yield when parsing the data.
Once inside the SoftSerial Rx interrupt handler any other interrupts shouldn't cause a problem because they would be disabled at that point. That is to say, as long as the initial entry latency is acceptable there should be no other threats to RxD parsing the data character.

- Thomas

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

Re: Nextion display plugin

#223 Post by BertB » 29 Jun 2018, 15:03

@ThomasB

I would like to do some experimenting myself.
So far I can see, the below is the rx interrupt service routine. Correct?

Code: Select all

void ICACHE_RAM_ATTR ESPeasySoftwareSerial::rxRead() {
   // Advance the starting point for the samples but compensate for the
   // initial delay which occurs before the interrupt is delivered
   unsigned long wait = m_bitTime + m_bitTime/3 - 500;
   unsigned long start = ESP.getCycleCount();
   uint8_t rec = 0;
   for (uint8_t i = 0; i < 8; i++) {
     WAIT;
     rec >>= 1;
     if (digitalRead(m_rxPin))
       rec |= 0x80;
   }
   if (m_invert) rec = ~rec;
   // Stop bit
   WAIT;
   // Store the received value in the buffer unless we have an overflow
   uint16_t next = (m_inPos+1) % m_buffSize;
   if (next != m_inPos) {
      m_buffer[m_inPos] = rec;
      m_inPos = next;
   }
   // Must clear this bit in the interrupt register,
   // it gets set even when interrupts are disabled
   GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << m_rxPin);
}
Where did you put your toggle bit and where do you see all intterupts are blocked, once in the rx interrupt routing?

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

Re: Nextion display plugin

#224 Post by ThomasB » 29 Jun 2018, 16:26

Here's the debug code:

Code: Select all

void ICACHE_RAM_ATTR ESPeasySoftwareSerial::rxRead() {
   // Advance the starting point for the samples but compensate for the
   // initial delay which occurs before the interrupt is delivered

   pinMode(5, OUTPUT); // DEBUG
   digitalWrite(5, HIGH);  // DEBUG
   
   unsigned long wait  = m_bitTime + m_bitTime/3 - 500;
//   unsigned long wait  = m_bitTime + m_bitTime/3 - 3000;  // Test
   unsigned long start = ESP.getCycleCount();
   uint8_t rec = 0;
   
   
   for (uint8_t i = 0; i < 8; i++) {
     WAIT;
     digitalWrite(5, LOW);  // DEBUG
     rec >>= 1;
     if (digitalRead(m_rxPin))
       rec |= 0x80;
       delayMicroseconds(1);   // DEBUG
       digitalWrite(5, HIGH);  // DEBUG
   }
   if (m_invert) rec = ~rec;
   // Stop bit
   WAIT;
   digitalWrite(5, LOW);  // DEBUG
   
   // Store the received value in the buffer unless we have an overflow
   uint16_t next = (m_inPos+1) % m_buffSize;
   if (next != m_inPos) {
      m_buffer[m_inPos] = rec;
      m_inPos = next;
   }
   // Must clear this bit in the interrupt register,
   // it gets set even when interrupts are disabled
   GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << m_rxPin);
}
You'll need either a 2-channel digital o-scope or logic analyzer. Sync on RxD and compare RxD to the toggled DEBUG bit. There will be a DEBUG bit event at entry (Latency measurement) into the function and at each bit reading (Data Alignment measurement).

Using the bit toggle you can mentally reconstruct the incoming data byte and determine if it is corrupt. You have to study each character of an entire string sentence message. And be patient, a corruption event is random when it affects a character in the 0Ah terminated string.

- Thomas


- Thomas

waspie
Normal user
Posts: 110
Joined: 09 Feb 2017, 19:35

Re: Nextion display plugin

#225 Post by waspie » 29 Jun 2018, 17:02

so there's no "canned" way to do the workaround?
ThomasB wrote:
29 Jun 2018, 16:26
Here's the debug code:

Code: Select all

void ICACHE_RAM_ATTR ESPeasySoftwareSerial::rxRead() {
   // Advance the starting point for the samples but compensate for the
   // initial delay which occurs before the interrupt is delivered

   pinMode(5, OUTPUT); // DEBUG
   digitalWrite(5, HIGH);  // DEBUG
   
   unsigned long wait  = m_bitTime + m_bitTime/3 - 500;
//   unsigned long wait  = m_bitTime + m_bitTime/3 - 3000;  // Test
   unsigned long start = ESP.getCycleCount();
   uint8_t rec = 0;
   
   
   for (uint8_t i = 0; i < 8; i++) {
     WAIT;
     digitalWrite(5, LOW);  // DEBUG
     rec >>= 1;
     if (digitalRead(m_rxPin))
       rec |= 0x80;
       delayMicroseconds(1);   // DEBUG
       digitalWrite(5, HIGH);  // DEBUG
   }
   if (m_invert) rec = ~rec;
   // Stop bit
   WAIT;
   digitalWrite(5, LOW);  // DEBUG
   
   // Store the received value in the buffer unless we have an overflow
   uint16_t next = (m_inPos+1) % m_buffSize;
   if (next != m_inPos) {
      m_buffer[m_inPos] = rec;
      m_inPos = next;
   }
   // Must clear this bit in the interrupt register,
   // it gets set even when interrupts are disabled
   GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << m_rxPin);
}
You'll need either a 2-channel digital o-scope or logic analyzer. Sync on RxD and compare RxD to the toggled DEBUG bit. There will be a DEBUG bit event at entry (Latency measurement) into the function and at each bit reading (Data Alignment measurement).

Using the bit toggle you can mentally reconstruct the incoming data byte and determine if it is corrupt. You have to study each character of an entire string sentence message. And be patient, a corruption event is random when it affects a character in the 0Ah terminated string.

- Thomas


- Thomas

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

Re: Nextion display plugin

#226 Post by ThomasB » 29 Jun 2018, 17:13

My workaround strategy was posted earlier. It involved sending each Nextion->ESP message string (|s format) multiple times and filtering the data in the ESP Rules by having MQTT only send valid idx codes.

- Thomas

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

Re: Nextion display plugin

#227 Post by BertB » 29 Jun 2018, 18:43

Below, a recording with a logic analyser, connected to a WeMos with a PMS5003 Dust detector attached.
It sends bursts of 32 bytes of data.
As you can see, somstimes a complete byte is not at all detected.
missing frame.PNG
missing frame.PNG (35.67 KiB) Viewed 3790 times

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

Re: Nextion display plugin

#228 Post by ThomasB » 29 Jun 2018, 19:09

Good stuff. My interpretation is that the second RxD character byte (ref CH0) has excessive latency on entry into the SoftSerial function. The initial debug bit (ref CH1, about +4ms marker time) demonstrates that the parsing sampling is delayed (because it appears too late in the incoming RxD's bit stream).

This causes the entire RxD char's bit order to be shifted after parsing. It will be a Nextion->ESP data character byte that is corrupted.

Edit: Also, to make it easier to measure the entry latency for each received character you should include the digitalWrite(5, LOW) statement after the stop bit's WAIT. See my posted code above.

- Thomas

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

Re: Nextion display plugin

#229 Post by BertB » 29 Jun 2018, 23:01

Well, the way I see it, ESP and serialsoft do not work reliably together, no matter how often we measure. Is am going to focus on good old hardware.

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

Re: Nextion display plugin

#230 Post by ThomasB » 29 Jun 2018, 23:10

My workaround coding has been a good band-aid for my Nextion project. It's been running for several days without any issues. But I agree with you and would not recommend the Nextion plugin due to the SoftSerial issue.

- Thomas

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

Re: Nextion display plugin

#231 Post by BertB » 01 Jul 2018, 00:25

Is managed to connect my dust sensor to the redirected hardware serial interface. It runs like a charm.

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

Re: Nextion display plugin

#232 Post by ThomasB » 01 Jul 2018, 02:47

Congrats on the success of your re-purposed serial port. Maybe it will encourage someone to do something similar for the Nextion Plugin.

I also had a bit of good news on my ESPEasy project. The MPU6050 gyro-accelerometer arrived yesterday. I am using it to detect when the laundry dryer is running (g-force vibration sensing). ESPEasy's MPU6040 [Testing] plugin works great for this. So thumbs up on that newly developed device plugin.

- Thomas

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

Re: Nextion display plugin

#233 Post by BertB » 01 Jul 2018, 08:21

I will try to put some effort in the nextion plugin next week.

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

Re: Nextion display plugin

#234 Post by BertB » 02 Jul 2018, 22:24

I was able to get a very quick and dirty code to connect the Nextion with the hw serial port.
After Serial.swap(), the Tx of the ESP is connected to GPIO15 (D8) and Rx to GPIO13 (D7).
There is a but.
Due to the fact that the Rx of the Nextion has a pull up resistor and GPIO15 must be low at boot-up, a direct connection is not possible.
I solved that problem with a single pnp transistor.
The collector is connected to GND, the emittor to Rx of Nextion and base to Tx of ESP.

Looks promising.

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

Re: Nextion display plugin

#235 Post by ThomasB » 03 Jul 2018, 00:40

Adding the transistor wouldn't be a problem for me. Looking forward to seeing your working code.

- Thomas

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

Re: Nextion display plugin

#236 Post by BertB » 04 Jul 2018, 20:11

Okay, I have something to try for you.
You will have to copy the code over the existing Nextion plugin code.
In the advanced settings, Enable Serial Port MUST be unchecked.
In the setup of the device, you have to select GPIO <- TX = GPIO-13 (D7) and for GPIO ->RX = GPIO-15 (D8).

Then on D7 connect Tx of Nextion.
For D8 you need to do something extra.
D8 = GPIO 15. This port has to be low at boot up. Nextions Rx had a relatively strong pull up. Result is that the ESP will not start when D8 is directly connected to Nextions Rx.
The following simple circuit helps you here. A simple PNP small signal transistor is ok to virtually reduce the pull up of the Nextion.

I cannot attach a picture ...

Connect the base to D8. Connect Collector to GND and connect Emittor to Rx of Nextion.

Code: Select all

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

#include <ESPeasySoftwareSerial.h>

#define PLUGIN_075
#define PLUGIN_ID_075 75
#define PLUGIN_NAME_075 "Display - Nextion [TESTING]"
#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
#define Nextion_SIG1 'c'
#define Nextion_SIG2 '|'

ESPeasySoftwareSerial *NswSerial = NULL;
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;
      success = true;
      break;
    }

    case PLUGIN_GET_DEVICENAME: {
      string = F(PLUGIN_NAME_075);
      success = true;
      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: {
      event->String1 = F("GPIO &larr; TX");
      event->String2 = F("GPIO &rarr; RX");
      event->String3 = F("GPIO &rarr; Reset");
      break;
    }

    case PLUGIN_INIT: {

      int rxPin = Settings.TaskDevicePin1[event->TaskIndex];
      int txPin = Settings.TaskDevicePin2[event->TaskIndex];

      String log = F("PMSx003 : config ");
      log += rxPin;
      log += txPin;
      addLog(LOG_LEVEL_DEBUG, log);

      if (swSerial != NULL) {
        // Regardless the set pins, the software serial must be deleted.
        delete swSerial;
        swSerial = NULL;
      }

      // Hardware serial is RX on 13 and TX on 15 (swapped hw serial)
      if (rxPin == 13 && txPin == 15)
      {
        log = F("PMSx003 : using hardware serial");
        addLog(LOG_LEVEL_INFO, log);
        Serial.begin(9600);
        Serial.swap();
        Serial.flush();
      }
      // Hardware serial is RX on 3 and TX on 1
      else if (rxPin == 3 && txPin == 1)
      {
        log = F("PMSx003 : using hardware serial");
        addLog(LOG_LEVEL_INFO, log);
        Serial.begin(9600);
        Serial.flush();
      }
      else
      {
        log = F("PMSx003: using software serial");
        addLog(LOG_LEVEL_INFO, log);
        NswSerial = new ESPeasySoftwareSerial(rxPin, txPin, false, 128); // 96 Bytes buffer, enough for up to 3 packets.
        NswSerial->begin(9600);
        NswSerial->flush();
      }

      Plugin_075_init = true;
      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));

      success = true;
      break;
    }
    
    case PLUGIN_TEN_PER_SECOND: {
String log;
      char __buffer[80];

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

      if (!Serial.available()) return false;
      while ((Serial.peek() != Nextion_SIG1 && Serial.peek() != Nextion_SIG2) && Serial.available()) {
        Serial.read(); // Read until the buffer starts with the first byte of a message, or buffer empty.
      }
      if (Serial.available() < 7) return false; // Not enough yet for a complete packet
    
      c = Serial.read();

      if (0x65 == c) {
        __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];
          
          log = F("Nextion : code: ");
          log += __buffer[1];
          log += ",";
          log += __buffer[2];
          log += ",";
          log += __buffer[3];

          addLog(LOG_LEVEL_INFO, log);
          success=true;
          return success;
        }
      } else if (c == '|') {
        i = 1;
        __buffer[0] = c;
        while (Serial.available() > 0 && __buffer[i] !=0x0d) {
          __buffer[i] = Serial.read();
          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);

        ExecuteCommand(VALUE_SOURCE_SYSTEM, __buffer);
      }
      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 (NswSerial)
          {
            delete NswSerial;
            NswSerial=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 = 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());

        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

TD-er
Core team member
Posts: 1339
Joined: 01 Sep 2017, 22:13
Location: the Netherlands
Contact:

Re: Nextion display plugin

#237 Post by TD-er » 04 Jul 2018, 21:50

Sounds like something that should be working.

I guess we should have a new mode to set all these settings at once to be able to use hardware serial for some plugins.

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

Re: Nextion display plugin

#238 Post by ThomasB » 04 Jul 2018, 23:37

Okay, I have something to try for you.
Great! I've used all my ESP8266 boards but have more coming. So it might take a week or two before I can give feedback.
I guess we should have a new mode to set all these settings at once to be able to use hardware serial for some plugins.
I agree. If porting EasyESP to the ESP32 is expected to be completed soon then I'd wait for it. That host has 3 hardware serial ports. Plus a second CPU core that could be dedicated to a virtual port like soft serial. But something tells me that the ESP32 port is going to take awhile, so adding hardware serial to ESP8266's Nextion plugin would be nice.

- Thomas

waspie
Normal user
Posts: 110
Joined: 09 Feb 2017, 19:35

Re: Nextion display plugin

#239 Post by waspie » 05 Jul 2018, 01:30

ThomasB wrote:
04 Jul 2018, 23:37
Okay, I have something to try for you.
Great! I've used all my ESP8266 boards but have more coming. So it might take a week or two before I can give feedback.
I guess we should have a new mode to set all these settings at once to be able to use hardware serial for some plugins.
I agree. If porting EasyESP to the ESP32 is expected to be completed soon then I'd wait for it. That host has 3 hardware serial ports. Plus a second CPU core that could be dedicated to a virtual port like soft serial. But something tells me that the ESP32 port is going to take awhile, so adding hardware serial to ESP8266's Nextion plugin would be nice.

- Thomas
the code for the esp32 at this stage is not near reliable enough. I fought with a few of them for a while before throwing my hands up and going back to regular ESPs

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

Re: Nextion display plugin

#240 Post by ThomasB » 06 Jul 2018, 22:49

@BertB:
The spare ESP boards arrived today and I tried out your hardware serial plugin. Good news, It works! I only had time for basic tests and I need to do more evaluation. But so far so good.

Code Revisions:
1. A minor tweak was needed. The legacy serial0 command processor was stepping on Nextion page messages sent by ESP.

2. To help me know which serial method is active I also changed the Nextion device setup labels for RX & Tx GPIO so that they show when hardware serial is in use.

My Nextion display has been installed in another project and I don't have a spare. So for code evaluation I'm using the Nextion IDE with a 3.3V compatible USB->Serial dongle. With this configuration I couldn't get the PNP "boot" transistor to work. The ESP board would boot, but serial communication was messed up. So I've removed it for now; I should have time next week to find the fix for this.

Here's the revised plug-in code:

Code: Select all

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

#include <ESPeasySoftwareSerial.h>

#define PLUGIN_075
#define PLUGIN_ID_075 75
//#define PLUGIN_NAME_075 "Display - Nextion [TESTING]"
#define PLUGIN_NAME_075 "Display - Nextion   [BERTB REV2]"
#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
#define Nextion_SIG1 'c'
#define Nextion_SIG2 '|'

ESPeasySoftwareSerial *NswSerial = NULL;
boolean Plugin_075_init = false;
boolean hwserial = 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;
      success = true;
      break;
    }

    case PLUGIN_GET_DEVICENAME: {
      string = F(PLUGIN_NAME_075);
      success = true;
      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;");
      }
      event->String3 = F("GPIO &rarr; Reset");
      break;
    }

    case PLUGIN_INIT: {

      int rxPin = Settings.TaskDevicePin1[event->TaskIndex];
      int txPin = Settings.TaskDevicePin2[event->TaskIndex];

      String log = F("PMSx003 : config ");
      log += rxPin;
      log += txPin;
      addLog(LOG_LEVEL_DEBUG, log);

      if (swSerial != NULL) {
        // Regardless the set pins, the software serial must be deleted.
        delete swSerial;
        swSerial = NULL;
      }

      // Hardware serial is RX on 13 and TX on 15 (swapped hw serial)
      if (rxPin == 13 && txPin == 15)
      {
        log = F("PMSx003 : using hardware serial");
        addLog(LOG_LEVEL_INFO, log);
        hwserial = true;
        Serial.begin(9600);
        Serial.swap();
        Serial.flush();
      }
      // Hardware serial is RX on 3 and TX on 1
      else if (rxPin == 3 && txPin == 1)
      {
        log = F("PMSx003 : using hardware serial");
        addLog(LOG_LEVEL_INFO, log);
        hwserial = true;
        Serial.begin(9600);
        Serial.flush();
      }
      else
      {
        log = F("PMSx003: using software serial");
        addLog(LOG_LEVEL_INFO, log);
        hwserial = false;
        NswSerial = new ESPeasySoftwareSerial(rxPin, txPin, false, 128); // 96 Bytes buffer, enough for up to 3 packets.
        NswSerial->begin(9600);
        NswSerial->flush();
      }

      Plugin_075_init = true;
      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));

      success = true;
      break;
    }
    
    case PLUGIN_TEN_PER_SECOND: {
String log;
      char __buffer[80];

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

      if (!Serial.available()) return false;
      while ((Serial.peek() != Nextion_SIG1 && Serial.peek() != Nextion_SIG2) && Serial.available()) {
        Serial.read(); // Read until the buffer starts with the first byte of a message, or buffer empty.
      }
      if (Serial.available() < 7) return false; // Not enough yet for a complete packet 
    
      c = Serial.read();

      if (0x65 == c) {
        __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];
          
          log = F("Nextion : code: ");
          log += __buffer[1];
          log += ",";
          log += __buffer[2];
          log += ",";
          log += __buffer[3];

          addLog(LOG_LEVEL_INFO, log);
          success=true;
          return success;
        }
      } else if (c == '|') {
        i = 1;
        __buffer[0] = c;
        while (Serial.available() > 0 && __buffer[i] !=0x0d) {
          __buffer[i] = Serial.read();
          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);

        ExecuteCommand(VALUE_SOURCE_SYSTEM, __buffer);
      }
      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 (NswSerial)
          {
            delete NswSerial;
            NswSerial=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 = 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());

        if (hwserial == false) {
            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
Thanks again for enabling hardware serial on the Nextion Plugin. I appreciate it.

- Thomas
Last edited by ThomasB on 07 Jul 2018, 17:14, edited 1 time in total.

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

Re: Nextion display plugin

#241 Post by BertB » 07 Jul 2018, 11:40

Good to hear your early results. Together we can make it a good plugin.
It would be nice if the choice for a serial port swap could be done with a checkbox option.

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

Re: Nextion display plugin

#242 Post by BertB » 07 Jul 2018, 17:18

ThomasB wrote:
06 Jul 2018, 22:49

My Nextion display has been installed in another project and I don't have a spare. So for code evaluation I'm using the Nextion IDE with a 3.3V compatible USB->Serial dongle. With this configuration I couldn't get the PNP "boot" transistor to work. The ESP board would boot, but serial communication was messed up. So I've removed it for now; I should have time next week to find the fix for this.


- Thomas
I think you might need a pull up resistor on the Rx side of the dongle.

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

Re: Nextion display plugin

#243 Post by ThomasB » 07 Jul 2018, 18:00

BertB wrote:
07 Jul 2018, 17:18
I think you might need a pull up resistor on the Rx side of the dongle.
That is something I was going to try, plus I have other ideas. I should be able to get back on it in a day or two.

But in the meantime, please check your PNP's installation and confirm your instructions are correct. Since the RX pin is the one to hold low during boot, it seems unusual that the PNP's base is connected to the RX pin.

- Thomas

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

Re: Nextion display plugin

#244 Post by BertB » 07 Jul 2018, 18:04

This is what I have done with the transistor.

I agree, it was a bit strange in the plugin settings, but GPIO15=D8=Tx has to be low at start up.
D7 = Rx and D8 is Tx
You have improved it in the code.
Nextiontor.png
Nextiontor.png (960.6 KiB) Viewed 3726 times

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

Re: Nextion display plugin

#245 Post by ThomasB » 07 Jul 2018, 18:16

Thanks, the image shows I misinterpreted the PNP wiring. I'll be back in a day or two after I add the buffer transistor.

- Thomas

r_255
Normal user
Posts: 32
Joined: 20 Nov 2015, 20:42

Re: Nextion display plugin

#246 Post by r_255 » 08 Jul 2018, 07:15

Nice, that you guys kind of solved the issue... !
Thanks to the family B i guess :lol:

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

Re: Nextion display plugin

#247 Post by BertB » 08 Jul 2018, 18:17

I had some very weird problems, so I went back to the basics, with only hw Serial.

It runs now on two nextions.

I am still far from satisfied regarding fault free coding.

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

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

Re: Nextion display plugin

#248 Post by ThomasB » 09 Jul 2018, 04:15

@ r_255
It's great that ESP Easy is Open Source firmware so we can make changes.

@BertB
I installed the PNP boot pin buffer according to your posted schematic. It is working, thanks!

I think it's only fair that I contribute a bit more to your Nextion plugin mods; I spent a few hours on it today and have both hardware and soft serial working.

I also saw your earlier comment about using a checkbox to do the port swap. I added a checkbox to enable hardware serial (which will port swap if the pins are D7 and D8). UART1 (USB) hard/soft serial is handled by the checkbox too. See attach screenshot for details to the checkbox.
nextion.jpg
nextion.jpg (99.68 KiB) Viewed 3648 times
An unexpected benefit to the new plugin is that I no longer need to use a separate USB->Serial adapter when developing code in the Nextion Editor. Setting the plugin to use RX GPIO3 and TX GPIO1 (UART1) allows the editor to talk directly to ESP Easy via ESP8266's USB port. No need to unplug the Nextion display either.

I didn't have enough free time to fully validate the latest changes. I'll post the code as soon as I confirm that there are no hidden bugs. Give me a day or two.

- Thomas

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

Re: Nextion display plugin

#249 Post by BertB » 09 Jul 2018, 19:39

Nice :D

TD-er
Core team member
Posts: 1339
Joined: 01 Sep 2017, 22:13
Location: the Netherlands
Contact:

Re: Nextion display plugin

#250 Post by TD-er » 09 Jul 2018, 23:33

Great job :)
If you're satisfied, I would like to see the code to merge with the main branch.

Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests