Start a new topic

Creating a Nextion Piano within Nextion Logic

This thread will show how to create a two octave piano all within the Nextion logic without the need for an external microprocessor.  As we go through the process of creating this piano, I will deal with a few techniques that may be useful in your projects.   Again special shout out to Steve (indev2) for tripping across the b[.id] component array.

This project will use the Nextion 3.5" Enhanced NX4832K035_011 <Order Here>

and the Expansion Board for the Enhanced Nextions <Order Here>


So grab the blank HMI, and let's get coding.


2 people like this idea

It was once asked what the expansion board might be useful for, and I honestly didn't think much until I finally wrapped my head around trying to get the music notes to play.  The first trials of trying to find fair sounds that could somewhat resemble notes - well, hard on the ears.  But after a little work, I finally have somewhat playable notes.  You'll need an Enhanced Nextion display for the pwm IO and the expansion board with the buzzer that we will pump pwm to. So now let's go through how to make a Nextion Piano.

Here we use 15 Text Components for the ivory keys and 10 Text Components for the ebony keys.  I chose the Text Component because without any .txt it is simple to create a colored square with, and is fairly lightweight on the memory and resources.  Text Components also come with a Touch Press and Touch Release event which we will use to change colors when pressed.  So let's set these up now from left to right.  Remember to alternate your text components for white, black, white, black.  In the end we want to have t0 to t24 matching the keyboard of the piano.

The Ebony Keys

The ebony keys are t1, t3, t5, t8, t10, t13, t15, t17, t20 and t22.  You can use multi-select. Set their .w to 25 and .h to 120.  Set their .bco to 0 (black) and their .pco to 33808.  Using the Define Custom Colors from the bco color selector, white is Red 0, Green 0, and Blue 0. Add to Custom Colors and press OK.  All the ebony keys should now have bco of 0.  Likewise using the Define Custom Colors from the pco color selector, 33808 is Red 128, Green 128, and Blue 128.  Set their .xcen to Center, .ycen to Down, .txt to empty, .txt-maxl to 2, .isbr to false. The ebony keys are placed every 31 pixels with six pixel spacing between them.  Line them up with the keyboard background exactly.  You can use the fine precision of 1 pixel adjustments using your keyboard arrow keys.  Once the ebony keys are placed, multi-select all ebony keys from left to right, and use the Toolbar Arrow Down (Bring Bottom).  This will renumber their .id's sequentially starting at 1.

The Ivory Keys

The ivory keys are t0, t2, t4, t6, t7, t9, t11, t12, t14, t16, t18, t19, t21, t23 and t24. You can use multi-select.  Set their .w to 30 and .h to 120.  Set their .bco to 65535 (white) and their .pco to 50712.  Using the Define Custom Colors from the bco color selector, white is Red 255, Green 255, and Blue 255. Add to Custom Colors and press OK.  All the ivory keys should now have bco of 65535.  Likewise using the Define Custom Colors from the pco color selector, 50712 is Red 192, Green 192, and Blue 192.  Set their .xcen to Center, .ycen to Down, .txt to empty, .txt-maxl to 2, .isbr to false. The ivory keys are placed every 31 pixels with only one pixel spacing between them.  Line them up with the keyboard background exactly.  You can use the fine precision of 1 pixel adjustments using your keyboard arrow keys.  Once the ivory keys are placed, multi-select all ivory keys from left to right, and use the Toolbar Arrow Down (Bring Bottom).  This will renumber their .id's sequentially starting at 1.

Multi-Select all keys and ensure their .y is set to 188, and if not set to 188.  From here on out when we select a key, we will be using the right-click on the mouse as this will not accidently move our keys out of alignment (since we just spent so much effort to align them).  So now the keys from left to right have sequential .objname from t0 to t24, with the ivory keys sequential .ids from 1 to 15, and the ebony keys with sequential .ids from 16 to 25.  Ordering the Text Component keys in this fashion will allow the key to be played even when selecting the space between the ebony keys.

The Numeric Variables

Now we add to our HMI design 25 numeric Variable Components sequentially with .objnames from va0 to va24, and with sequential .ids from 26 to 50.  This will help shorten our code when we are able to employ the b[.id].attribute Component Array later on.

The Hotspot

We have to add one Hotspot Component m0 at .id 51 - this will hold two segments of code.  Set its .w to 32 and .h to 24 and set down close to "Note" where it wont get pressed.

The Number Components

Lastly we have the 4 Number Components from n0 to n3 with .ids from 52 to 55.  You can use multi-select.  Set their .w to 40 and .h to 16.  Set their .bco to 16904 (dark) and their .pco to 0.  Using the Define Custom Colors from the bco color selector, white is Red 64, Green 64, and Blue64. Add to Custom Colors and press OK.  All the numbers should now have bco of 16904.  Likewise using the Define Custom Colors from the pco color selector, 0 is Red 0, Green 0, and Blue 0.  Set their .xcen to Right, .ycen to Up, .val to 0, .lenth to 0, .isbr to false. The numbers are placed evenly after Freq (n0), Duty (n1), Key(n2) and Note(n3).  Line them up, multi-select them and set their .y to 163.

Lastly if you started this from scratch you would have to add your 1 font 8x16, and the piano background, and set the piano picture pic 0 for the page0 background.  Setting a page background is done by changing the page component's .sta to image and then setting the .pic to 0 by selecting your piano background from the pictures selector.

So now our piano should look okay, the ebony keys should appear to be on top of the ivory keys. Soon off to the coding.

Hmm, okay good new or the bad new first?

The good news is each of the Number Components have no Press/Release Code.  So let's dig right in and get this bad new done with.

May as well dig into the keys.  To make our code easier we are going to pass our key press over to the hotspot for processing.  So in every key we have a sys0 equal to the Text Components .id attribute - 1.

In every touch Press Event, we call our hotspot with click m0,1, every Release has click m0,0.  So most of this would be pure repetition:

t0 Touch Press Event would look like:


  click m0,1

t0 Touch Release Event would look like

  click m0,0

t1 Touch Press Event would look like:


  click m0,1 t1

Touch Release Event would look like

  click m0,0

If we are just looking to get our notes to play, this will do it.  We carry this pattern through to t24

t24 Touch Press Event would look like:


  click m0,1

t24 Touch Release Event would look like

  click m0,0

But we also want to give our buttons some color when they are pressed and return when released.
Here it gets a bit more complex.  The design is such that as it is now, if I press an ivory key at its top between two ebony keys - it will play as the white ivory key is the Text Component below the two edges of the ebony keys.  This trait I want to keep, so we have more work to do to make it happen.  So first let's deal with the 10 ebony keys.

Each ebony key will have to set its .bco=8452 in the Press Event and back to .bco=0 in Release.  This is fairly straight forward.  So the total code for t1 looks like:
t1 Press Event:
  t1.bco=8452 // just added
  click m0,1
t1 Release Event
  t1.bco=0  // just added
  click m0,0
You can make these changes to the ebony.  Replace the t1 with the appropriate .objname.

And the only ivory key that matches this pattern is t24, using 50712 and 65535
t24 Press Event:
  t24.bco=50712 // just added
  click m0,1
t24 Release Event
  t24.bco=65535  // just added
  click m0,0

But why can't we do this for the other ivory keys?

The answer is that if we set its color by .bco, it will bring it to the upper layer when it is refreshed.  This will cause the ivory keys to overlay the ebony keys and it will certainly not look right.  After a few notes played, the only thing left of the ebony key will be a very thin strip of black.  We need to use a different approach if we want to keep our look, feel and functionality of our ivories.

So for all of our ivory keys we are going to implement the fill command.  There two sections of an ivory key.  One of these blocks is a 30x40 at .y of 268 and the other is a height of 80 at .y of 188

So the t0 Pressed Event looks like:


fill 7,268,30,40,50712

fill 7,188,18,80,50712

click m0,1

t0 Release Event looks like:

fill 7,268,30,40,65535

fill 7,188,18,80,65535

click m0,0

Now to save some time from typing this all out right here, I am going to attach a notepad file so that all the ivory and ebony event codes can be copied into their respective events.  So I'll let you get this portion accomplished while I prepare for the next section.

(3.22 KB)

So I am going to now we are going to throw a curve.

- A new feature, more work.  How about key names on the keys?

So, if you want this feature, we will have to redo the key events again.

Here is what we need do:

- Create a new number variable, change its .objname to names

- Create a new hotspot, change its .objname to snames

  - set its .w to 18, .h to 24, .x to 216, and .y to 158

The snames Hotspot needs its Touch Press Event set to include:















   xstr 7,292,30,16,0,50712,65535,1,1,1,"F"

   xstr 38,292,30,16,0,50712,65535,1,1,1,"G"

   xstr 69,292,30,16,0,50712,65535,1,1,1,"A"

   xstr 100,292,30,16,0,50712,65535,1,1,1,"B"

   xstr 131,292,30,16,0,50712,65535,1,1,1,"C"

   xstr 162,292,30,16,0,50712,65535,1,1,1,"D"

   xstr 193,292,30,16,0,50712,65535,1,1,1,"E"

   xstr 224,292,30,16,0,50712,65535,1,1,1,"F"

   xstr 255,292,30,16,0,50712,65535,1,1,1,"G"

   xstr 286,292,30,16,0,50712,65535,1,1,1,"A"

   xstr 317,292,30,16,0,50712,65535,1,1,1,"B"

   xstr 348,292,30,16,0,50712,65535,1,1,1,"C"

   xstr 379,292,30,16,0,50712,65535,1,1,1,"D"

   xstr 410,292,30,16,0,50712,65535,1,1,1,"E"

   xstr 441,292,30,16,0,50712,65535,1,1,1,"F"














   fill 7,292,30,16,65535

   fill 38,292,30,16,65535

   fill 69,292,30,16,65535

   fill 100,292,30,16,65535

   fill 131,292,30,16,65535

   fill 162,292,30,16,65535

   fill 193,292,30,16,65535

   fill 224,292,30,16,65535

   fill 255,292,30,16,65535

   fill 286,292,30,16,65535

   fill 317,292,30,16,65535

   fill 348,292,30,16,65535

   fill 379,292,30,16,65535

   fill 410,292,30,16,65535

   fill 441,292,30,16,65535


And of course all the ivory and ebony codes will need to include painting the names in the keys Touch Press and Touch Release Events.  So just as before, I will leave you with the notepad file with their respective codes for you to replace into each of their respective events.

(6.47 KB)

So what do we have so far.  Our keys are in place, they can be named or not (depends if you did the step above).  The keys are colored when pressed.  And they keys will pass to the m0 hotspot which key is pressed to generate our notes. ... our notes.

the Base Notes

So here is why we had our 25 sequential numeric Variable Components, so that if need be, we will have one spot where our notes can be tweaked.  Perhaps we prefer to lower the tones a bit at some other time.  We do not need to go through the 25 individual variables one by one, we will have a nice list where these are included in one simple spot .. inside the page0 Page Component's Postinitialize Event. 

This Postinitialize Event will do two things. The first task is to set our names and label our keys with click snames,1 for those that did the above step, or it should be commented out for those that did not do the above step by adding two forward slashes at the beginning of the line like //click names.val,1.  The second task is to initialize our variables va0 to va24 with our notes frequencies.  So our Preinitialize Event should look like:

click snames,1


























Now all that remains is getting these notes to play through the buzzer on IO7 of the expansion board.

So okay you have connected your Expansion board to your Nextion using the 10 pin FFC cable, All is looking okay from a connection point -- So lets get that buzzer buzzing.

Dealing with Pulse Width Modulation

There are four steps that we need to deal with for our pwm through IO7

1) First we need to set our duty cycle, this is a percentage of time voltage is HI.


    This will evaluate on the Nextion simply as 11.  I left the divisor there to make it simple to adjust.

2) Second we need to configure our gpio pin for IO7.

    cfgpio 7,3,0

    This sets IO7 (7) to PWM output mode (3) and 0 is technically the page component

3) Third we need to set our PWM frequency.


     here sys0 passes our key number and grabs the frequency from our sequential set of variables.

     The keys start at 0, the va0 series starts with .id 26 and now you see why it was important to make

     sure that the components were sequentially ordered.  For ease ... great ease.

The PWM for our piano sounds better with a multiplier, and with some tinkering 3 makes it fine.

At this point, we may as well also set our four numbers. So our m0 hotspot pressed event code:

pwm7=100/9   // Set our duty cycle

cfgpio 7,3,0     // enable pwm on IO7

pwmf=b[sys0+26].val*3  // set our pwm frequency

n0.val=b[sys0+26].val*3 // Display our pwm freq in n0

n1.val=100/9           // Display out Duty cycle in n1

n2.val=sys0            // Display our Key Number in n2

n3.val=b[sys0+26].val  // Display our base note in n3

But now I did say there were 4 things and we dealt with only three.  Our PWM on IO7 will stay configured exactly as we configured it.  This will result in the same note being played over and over, and regardless if some musicians sound like that is all they are playing is one note, we demand better.  So we need to unconfigure the PWM between uses.  So every key release event calls our hotspot release event with click m0,0 -- so in here we have only one line that disables our pwm.  So m0 Release Event is:

cfgpio 7,1,0

   - Here we simply set IO7 to input binding mode to our page. 

There is no other reason why binding to the page other than it disabled our PWM as we needed.

An there you have it - a playable Nextion Piano all within Nextion logic ...


We will expand this later on ... the Pla-ya Pian-na !  Oh yeah.

(374 KB)

Spending a bit of time of your new Nextion Piano, there are many things that are possible.


As you can see, I have continued forward to add a key indicator at the bottom of the keys,

Key's Named if desired, a scrolling score, and added five player piano Christmas Carols

So, carry on and have loads of fun.

Login or Signup to post a comment