Seithan / EasyNextionLibrary

A simple library for Nextion display that uses only four functions. You can easily benefit from Nextion's wide range of features and advantages in just a few easy steps. The library uses a custom protocol that can prove to be a powerful tool for advanced users as it can be easily modified to meet one’s needs.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Example with len superior of 02

plckr opened this issue · comments

I cannot find any example with second parameter (len) superior of 02
I tried to do this to catch the next 3 bytes:

Nextion button:

printh 23 03 4c 01 01

C++ code:

    case 'L':
      Serial.println(_serial->read());
      break;

the above code reports 01 only, and not the entire combination like "01 01"

Is there anything to combine both in single variable?
Or how do you do in your cases?

EDIT: when first posted I said it reports twice but I was wrong. It is reporting only once

Hello,

From what I can understand, you are using the custom commands, with one new command group "L".

You are receiving only one, because with Serial.println(_serial->read()); , you read only one byte. To read the next byte, you will need to make one more _serial->read()

In your example, you will to write one more time Serial.println(_serial->read());

Also, len is used for us to know if all the bytes arrived. It is also used to know how many bytes we are going to have to handle in the code.

Whatever you need, do not hesitate to write :)

Ok, I get it.
Anyways, one suggestion is to pass the content based on the length inserted into the custom command, I think it's more useful that way for the user

for example, you can capture the content, store it in a class variable and call the function, then in user custom commands, anyone can call that variable to get the value more easy

EDIT: Or maybe more efficient, declare a weak function for custom commands, and if command isn't "P" or "T", it calls the weak function with two parameters, the command letter, and the content based on the . That way, the user don't need to change the library files, staying it intact

Didn't tested, but here's the idea
header file

extern void readCustomCommand(); 
extern void readCustomCommand() __attribute__((weak));

readCustomCommands.cpp

void EasyNex::readCommand(){
  switch(_cmd1){
    case 'P':
	  /* code here for P */
      break;
	  
    case 'T':
	  /* code here for T */
      break;
  }
	  
  /* _data computed and stored in class variable before reaching here */
  readCustomCommand(_cmd1, _data, _len);
}

I understand your point .
For that reason we have the trigger functions, where there are declared as weak attribute extern void trigger1() __attribute__((weak));
So a user can easily and without modifying the library's files call a trigger() and read or write any value at any variable or run a piece of code.

The readCustomCommands has a different meaning and it is used for a custom protocol feature. You can read about it at this link:
https://seithan.com/Easy-Nextion-Library/Custom-Protocol/

I also have in mind to make the custom protocol as a weak function but as it is a very special feature and only advanced on programing users can use it, it is not necessary for them, as they can easily modify the .cpp file of the library.

It will be good to avoid modifying on library's file, as an update of library can erase the custom code.
I will do that in next update (declare the customProtocol as weak and make the add-ons from the code).

examples for trigger function

void trigger1(){
int x = 22;  // set value of variable x equal to 22

x = myNex.readNumber("n0.val");   // We read the value of n0 and store it to number variable

}

If you want to capture a value or to turn ON/OFF a relay you don't have to complicate it with a custom protocol as you simply use the trigger function.
See at trigger example of the library

https://github.com/Seithan/EasyNextionLibrary/blob/master/examples/Trigger/TriggerCode/TriggerCode.ino

I hope that I have answered your questions.

In the last days, I spent reading your docs, some of them more than once to fully understand how this library works.
I really understand the trigger function, but for me, I find it not appealing because function names like trigger1 makes no sense when you have a lot of triggers. In my case, I'll have maybe 40 triggers for the letter L, more 10 for letter 'S', and probably more will come.
Sure I can edit the library source code, but I'm using platformio for programming, and sometimes platformio downloads the library, making my changes deleted

Ok, for the moment and until I make the changes, you can write the code for case letter L in a function in your code, like
void letterLCase(){ // code for read bytes etc }

and you can call it from readCustomCommands.cpp with only one line

void EasyNex::readCommand(){
  switch(_cmd1){

    case 'L':
	letterLCase();
      break;

    case 'P':
	  /* code here for P */
      break;
	  
    case 'T':
	  /* code here for T */
      break;
  }
	  
}

Also an array like this always helps to handle many cases

const uint8_t TOTAL_RELAY = 6    // How many warning relays we use


const uint8_t relayPin[TOTAL_RELAY] = {2, 3, 4, 5, 6, 7};  // assigns the pin number for every relay
 /*
  * Declare that pin D2 is the pin that controls the Relay No0 (front lights)
  * Declare that pin D3 is the pin that controls the Relay No1 (Backyard lights)
  * Declare that pin D4 is the pin that controls the Relay No2 (swimming pool lights)
  * Declare that pin D5 is the pin that controls the Relay No3 (roofgarden lights)
  * Declare that pin D6 is the pin that controls the Relay No4 (adviser lights)
  * Declare that pin D7 is the pin that controls the Relay No5 (extra auxiliary lights)
  */

I did some changes in your code, and it seems to work as expected, I didn't coded the data variable but the rest is working.

At the end of the EasyNextionLibrary.h

extern void easyNexReadCustomCommand(uint8_t _cmd1, uint8_t _len);
extern void easyNexReadCustomCommand(uint8_t _cmd1, uint8_t _len) __attribute__((weak));

readCustomCommands.cpp

void EasyNex::readCommand(){		
  switch(_cmd1){
    case 'P': 
      /* code */   
      break;
      
    case 'T':
      /* code */
      break;

    default:
      easyNexReadCustomCommand(_cmd1, _len);
}

In my main.cpp -> Example of incoming serial data -> printh 23 03 4c 01 01

void easyNexReadCustomCommand(uint8_t cmd1, uint8_t len) {
  Serial.println(cmd1, HEX); //This is reporting the letter as expected -> 4C
  Serial.println(len); // Reporting the correct length -> 03
}

The only thing left is the content being captured and passed into the function.
What do you think?

let me see it more carefully

if you can point me the direction to catch the data, I can try to make a pull request if you want

  • Declare that pin D2 is the pin that controls the Relay No0 (front lights)
  • Declare that pin D3 is the pin that controls the Relay No1 (Backyard lights)
  • Declare that pin D4 is the pin that controls the Relay No2 (swimming pool lights)
  • Declare that pin D5 is the pin that controls the Relay No3 (roofgarden lights)
  • Declare that pin D6 is the pin that controls the Relay No4 (adviser lights)
  • Declare that pin D7 is the pin that controls the Relay No5 (extra auxiliary lights)

This is the way I'm using.
I'm using an Array of Objects, one Array for letter L, another for S

This example mentioned earlier printh 23 03 4c 01 01 defined both the id of the Array and the state it should change (00 or 01)
And for letter S the first Byte is the id, and the second is a number between 0 and 100 (percentage)

Ok,
This seems nice approach, as I have it in my mind.

  1. we do not need the len, as len used to declare the number of bytes we are waiting in order to have a completed command
  2. void easyNexReadCustomCommand must be in the code (.ino file) I believe with main.ccp is the user code in the compiler that you are using

so the code inside the void easyNexReadCustomCommand is uppon the user is that right?

if you can point me the direction to catch the data, I can try to make a pull request if you want

No problem with the point to the direction
As for the pull request I believe that it will be better to make the changes my self and of course to mention your name for the help on that

  1. I don't need the len in my code, until for now atleast. But could be useful if the Group Letter have different lengths.
  2. Correct!

If user wants to implement Group Commands/Letters, he has to declare the function himself. If don't, just ignore and don't declare.

Will you intend to implement the data being parsed into the function?
I think that would be very useful.

So from users code file you can use the switch function again
For more accurate code you must tell me what the id's is going to used for,
example you only need to change the value of the array?

This is an example of my idea

void easyNexReadCustomCommand(uint8_t cmd1, uint8_t len, char data) {
  switch(cmd1){
    case 'L':
      lights[(int)data[0]].setState((int)data[1]);
      break;
    
    case 'S':
      shutters[(int)data[0].setLevel((int)data[1])];
      break;
  }
}

Something like this, if it makes sense

Where Serial the Serial you are using for Nextion

void easyNexReadCustomCommand(uint8_t cmd1) {
 int cmd1 = cmd1;
  switch(cmd1){
    case 'L':
      data[Serial.read()] = Serial.read(); //EDITED
// read the fist byte and use it to point the place of the data array
      // read the secont byte and set the data["first byte we read"] place equal with the value of the second byte
      break;
  }
}

Is that working?

Will you intend to implement the data being parsed into the function?
I think that would be very useful.

we must avoid to parsed the data into the function as this will be for general use and we don't know the needs of each user as someone may need to specify more than two ids

int cmd1 = cmd1; <- This is here by mistake (?)

For my case, it seems more useful to do like this:
lights[(int)data[0]].setState((int)data[1]);

About your example, it seems more useful to expose _serial as public, that way the user don't call the wrong Serial by mistake

Anyways, I think it's useful to pass either the len or the data itself

we must avoid to parsed the data into the function as this will be for general use and we don't know the needs of each user as someone may need to specify more than two ids

data can be parsed and not used, atleast the user has the ability to use that more easily.
It has to be documented in the docs that if anyone that wants to use this function needs to declare the function in their code just like it is. What do u think?

int cmd1 = cmd1; <- This is here by mistake (?)

No it is not by mistake it better to save the parsed data in a variable before you use them ( maybe uint_8 is better)

For my case, it seems more useful to do like this:
lights[(int)data[0]].setState((int)data[1]);

First we must keep the functions for general use, I cannot think a way to read the data for the library as those data can vary for user to user. So the way is to read the next bytes from the void easyNexReadCustomCommand and assign them.

lights[(int)data[0]].setState((int)data[1]);

I don't understand this command

About your example, it seems more useful to expose _serial as public, that way the user don't call the wrong Serial by mistake

This comes second at this time as a new function for serial read can de added ( myNex.read();) in the library, _serial is only for the use inside the library

data can be parsed and not used, at least the user has the ability to use that more easily.

The most easy and reliable and keep the general purpose of the library is to read and assign the data from the user code

data can be parsed and not used, atleast the user has the ability to use that more easily.

Yes but how many data we must read?
And how many variables we must create and with what names?

Isn't more creative to let the used do that upon its needs?
What if a user need to have not only 2 croup commands but 10 and have to use 10 letter ?

We must keep it as simply as we can, a full documentation of two or more pages is not simply use.
What do you thing?

I don't understand this command

This is just an example of my code, isn't about your library. In my case I have an array of Light Objects, the first byte is the ID of the array, and the second byte is the state to change. So, the code posted is an example to catch those two bytes and put into action. Just for sharing, so you can understand better


I'll make some examples

Example 1

Nextion
printh 23 03 4c 01 01

easyNexReadCustomCommand(cmd1 /*'L'*/, data /*[01, 01]*/);

Example 2

Nextion
printh 23 02 50 03

easyNexReadCustomCommand(cmd1 /*'P'*/, data /*[03]*/);

Example 3

Nextion
printh 23 05 4b 03 04 00 01

easyNexReadCustomCommand(cmd1 /*'K'*/, data /*[03, 04, 00, 01]*/);

PS: The above code is just for understanding what's underneath the variable names when calling the function

I hope this makes sense.
If you don't want to add extra code to catch all the entire data, just provide the len so the user can loop through correct number of iterations. Because it can be dynamic, not always the same length

You are right I don't want to add extra code to catch all the entire data as it is dynamic and it is going to be very compilated.

I am going to add

  • easyNexReadCustomCommand()
  • a Serial read function for the class of EasyNex ( myNex.read() ) for reading the bytes from the correct Serial
  • I will declare 2 global variables cmd an len so anyone can call them from anywhere and use them in the code
    as for simplicity reasons user can declare the function this way easyNexReadCustomCommand(); and not like easyNexReadCustomCommand(int cmd1,int len); while the cmd and len will be available from the global variables

Is that OK?

Yes, seems ok that way.

myNex.read() will be the same as Serial->read()?

Yes, seems ok that way.

myNex.read() will be the same as Serial->read()?

Yes, and you could call it from the main code

Ok, nice.
Excited to test it

Ah, one thing I noticed, maybe could be useful to trigger the function for P Group Commands, I find it useful to make changes when a page changes. Or is it better to read the currentPageId from the library in the loop?


use case

When page changes, arduino sends the requires data into the nextion so can update the components

I think that we are OK now.
I made some test for the new function's and I have a nice example for those.
Make your own Test and I am waiting for the results.

customProtocolMod.zip

I think that we are OK now.
I made some test for the new function's and I have a nice example for those.
Make your own Test and I am waiting for the results.

customProtocolMod.zip

The files is attached, forgot to mention it.

I made some tests, and everything seems to work good 👍

Ok
It is very good that you also ran some test and you have confirmed that it is working well.

I am going to do some test with the other examples to check the compatibility and I will start writing comments and documentation and I will begin to make the new release.

Thank you for your help :)

Can you please create a new branch and publish the code to there? That way is much easier to start fully working and testing

I find this way more complicating, for me at least. I prefer the new releases and also I have done some work already and I have made other changes in the code, to other functions .

Just give me some time to finish it.

I noticed you added new files, can I test with those or is incomplete?

A new release was just published.
Give it a try!

If we do not need this issue, close it whenever you want :)

So far, everything is working as expected.
I'm gonna close this issue
Thanks again, for all of your collaboration