PXT coding tutorial - bitty mood lighting

micro:bit code

Your micro:bit needs the right code on it to be able to respond to buttons being pressed and it being tilted to change the current colour on your tablet's screen.

As with all our apps you can simply download and install a hex file which we've prepared for you or you can code it yourself, following the Bitty Software coding tutorial below. Naturally, we recommend you code it yourself!


requirements

From the user's point of view, and without worrying yet how this will be accomplished, here's what we want:

  1. Button B - The user must be able to unlock the currently displayed colour, so that they can change it, by pressing micro:bit button B. Pressing button B while the colour is unlocked must return it to a locked state so that it can no longer be changed. When locking, the system must also save the newly selected colour.
  2. Button A - All colours on the screen are a mixture of 0 - 255 parts of red, green and blue. When the system has been unlocked by pressing button B, the user must be able to increase or decrease the red, green or blue part of the current colour. Pressing button A will switch the current colour part from red to green to blue and back to red again. The micro:bit display should indicate the current colour part which is selected by displaying 'R', 'G' or 'B'.
  3. Button A+B together - When buttons A and B are both pressed together, the system must go into "standby mode' and display a black screen. If it is already in standby mode when A+B are pressed, it should come out of standby mode and enter 'active mode', displaying the last colour to have been selected.
  4. Left and right tilting - with the colour unlocked (pressing button B), tilting the micro:bit to the right (with the display facing up) should increase the selected colour part of red, green or blue while tilting to the left should reduce it. Tilting to a greater angle from the horizontal should make the rate of change proceed faster. Tilting less should make the change proceed more slowly to allow fine tuning.

choices

There are at least a couple of different ways to create a system which responds to the micro:bit buttons and to movement or tilting.

  1. The micro:bit's Bluetooth 'profile' includes "services' (like components or modules) called the Button Service and the Accelerometer Service. The Button Service can send messages over Bluetooth to a connected device whenever a button is pressed, held down for more than 2 seconds or released. The Accelerometer Service can send a stream of X,Y and Z values to describe the raw motion of the micro:bit. We could use these services and have the smartphone code do all the hard work to process that data and decide how to respond to it. The micro:bit would need very little code for this approach to be used, other than to ensure these two Bluetooth services are enabled.
  2. We could alternatively send information over Bluetooth in the form of special messages known as "events" from the micro:bit to the smartphone. The code on the micro:bit would indicate actions it wants the smartphone to take instead of sending it raw data about button presses or movement. To do this, the micro:bit code would need to process button and motion data and make decisions about what this should mean to the connected phone or tablet. The micro:bit does more of the work and the smartphone a bit less in this approach.
  3. Alternative system designs like this, where we have to decide which part of our system will be responsible for which aspect of the logic, are known as the System Architecture.
  4. There are pros and cons in each of these two approaches but option 2 lets you learn more about micro:bit coding. So we'll proceed with option 2!

goals

Our micro:bit code needs to:

  1. Keep track of whether or not something is connected to the micro:bit over Bluetooth
  2. Keep track of its own state, whether "locked" or "unlocked" and to change this state when button B is pressed.
  3. Cycle through the selected colour part of red/green/blue when button A is pressed and in the unlocked state (because button B was pressed).
  4. Send the connected smartphone data values which indicate which colour part should be changed and by how much, when in an unlocked state and the micro:bit is tilted more than, say +/- 5% from the horizontal
  5. Send the smartphone data which means "go into standby mode" or "go into active mode" when buttons A and B are pressed together.

before you start

You should install the bitty mood lighting application on your phone so you can use it for testing whilst you develop the micro:bit code. Check the bitty mood lighting page for details of where to find the app for your type of phone or tablet.


step 1 - PXT

Go to the PXT web site in your web browser or if you're already there, start a new project by clicking on the menu icon and then New Project.

Delete any blocks that are created automatically. We don't need them.


step 2 - make sure your project includes the right packages

Packages

PXT groups function blocks together in "packages" and these are listed in a column. A screenshot of a list of PXT packages is shown above. By default it includes a package called "Radio" which allows you to use a very simple wireless capability of the micro:bit. "Radio" is good if you want to broadcast a short string of characters to any / all micro:bits around. It's not Bluetooth and is not what we need for the bitty mood lighting application. Most importantly, a PXT project cannot include both the Radio package and the Bluetooth package at the same time. Add the Bluetooth package to your project and when prompted to, choose to remove the radio package.

Click on the menu icon, Add Package and select the bluetooth package.

When prompted, opt to remove the radio package


step 3 - create some variables

We're going to use a number of different variables, for the following purposes:

  1. to tell us whether or not something has connected over Bluetooth
  2. to indicate whether the ability to change the colour is locked or unlocked
  3. to indicate whether the system is in the standby state or not
  4. to indicate what the current "colour part" (red, green or blue) it is that we're changing

and so on. You'll get a clearer idea of what our variables are used for as we progress through the steps in this tutorial. For now, we'll create a series of variables so that we can use them when we need them.

From within the "Variables" package, click on the "Set item to 0" block to add it to your project. Click on Item and select New Variable. Type the name "connected" and press enter. Now right click on the block and select "Duplicate". Click on the variable name, select New Variable and type the name of the next variable you need to create, using the image above as your guide. Keep repeating this sequence of tasks, duplicating your previous variable block and creating a new variable each time until all the variables we need have been created.


step 4 - display a start-up message

Next, we'll add a start-up message to be displayed on the micro:bit when it starts.

In the Basic tray, click on the "show string" block to add it to your project. Change the text to "ML" (for Mood Lighting!) and drag the block to snap to the variable blocks above it.


step 5 - Bluetooth connection tracking

Now we'll use some of the blocks in the Bluetooth package to add connection tracking to our project. What we'll do is set the "connection" variable to 1 whenever a connection is established and display "C" on the micro:bit display or we'll set the variable to 0 and display "D" if a connection gets dropped. We'll also reset some of our other variables to initial values whenever we accept a new connection.

From the Bluetooth tray, click on the "on bluetooth connected" block and then the "on bluetooth disconnected" block to add them to your project. Snap them to the previous block, one after the other. Then add "set variable" blocks and "show string" blocks as shown, inside each of the bluetooth connection event blocks.


step 6 - button A

When button A is pressed, we want to change our "colour" variable so that it represents the next colour part of red, green or blue, in that order, with 1 meaning red, 2 meaning green and 3 meaning blue. If we currently have blue selected, pressing A again must cause red to be the selected colour part and the "colour" variable will have a value of 1 once again. We only want to do this if there is a Bluetooth connection and if button B has been pressed, putting the system into the "unlocked" state, meaning we can now change the colour by tilting the micro:bit.

From the Input tray, click on the "on button A pressed" block to add it to your project. From the Logic tray, grab an If/Then block and snap it inside your new button handler block. Build the complete set of code blocks for button A until it matches the image above. If you have difficulty, watch the video to see how we did it.


step 7 - button B - state change and Bluetooth event

When button B is pressed, if the system is in the "locked" state, we want to put it into the "unlocked" state, meaning we can now change the colour by tilting the micro:bit. Alternatively, if it's already unlocked, we want to switch it back into the locked state. In either case, we want to inform the bitty mood lighting app that this change has happened by sending it an 'event" over Bluetooth. There are other things we want to do when we unlock the system, but let"s build this part of our code one small step at a time.

From the Input tray, click on the "on button A pressed" block to add it to your project. Use the drop down to change it so that it will handle button B being pressed rather than button A.

From the Logic tray, grab an If/Then block and snap it inside the button B handler block. Add a condition which checks for the "connected" variable having a value of 1, meaning we have a Bluetooth connection from the tablet or smartphone.

Inside the If block, set the colour_unlocked variable to the "opposite" value by multiplying it by -1. If it was -1 to begin with, meaning "locked", this will give it a value of 1 meaning "unlocked". If it was set to 1, multiplying it by -1 will set it to -1. Using -1 in this way is an nice easy way to swap backwards and forwards between two states.

From the Control tray, select a "raise event" block and snap it inside the button B handler block as shown. Set the source to 9006, which is the event ID we need to use for bitty mood lighting and set the value to 14, which to the bitty mood lighting app means "locked/unlocked state has changed".

Remember, if you have difficulty, watch the video to see how we performed each step.


step 8 - button B - get ready / reset

Now, if the system has been unlocked, we need to do a couple of things before we start handling the micro:bit being tilted. We need to set the colour variable to 1 so that red is the first colour part we start to change and we need to display "R" on the LED display so that the user knows red is the current colour. If the system was just locked, we just need to clear the screen.

Add another if/else block to the button B handler, underneath the "raise event" block as shown in the graphic below and use other blocks until you have exactly the same as is shown here.


step 9 - button B - measure micro:bit tilt in background

With the system unlocked, we now need to monitor the amount that the micro:bit is being tilted by, measured in degrees from the horizontal. We need to do this quite frequently so that the changes which take place on the screen of the tablet seem nice and smooth but we also need to do it in such a way that we don't block other processing which might happen at the same time, like the buttons being pressed.

To accomplish this, we'll add a while loop which will contain the tilt monitoring code but it will pause for 100ms after each measurement is taken and, most importantly, it will run in background. This means that other processing can take place at the same time, with little interference between our tilt measurement processing and any other processing. This is an example of quite an advanced topic known as "concurrency".

From the Control tray, add a "Run in background" block to the most recently added If block, as shown in the graphic below. Inside it, add a While true loop block from the Loops tray and set its condition part so that the loop will keep running as long as we still have a Bluetooth connection and the colour_unlocked variable indicates that the system is unlocked so that the current colour can be changed. Remember that this is indicated by the colour_unlocked variable having a value of 1.

Inside the While loop, add code which will measure the amount the micro:bit is being tilted to the left or right. In PXT, this quantity is called "roll". Use the "rotation" block from the Input tray and assign it"s value to your "roll" variable. Make sure you click on the rotation block's drop down menu to change the rotation value being measured from "pitch" to "roll".

From the Basic tray, add a "pause (ms)" block and set it to pause for 100ms.

Your button B handler should now look like this:


step 10 - button B - calculate and report the amount of colour change required

To finish the code required to handle button B, we need to perform a calculation whose result will indicate which direction of colour change is being requested (less red or more red for example) and how large a change. We then need to send this information, together with a number which indicates which particular colour part is to be changed (red/green/blue) to the bitty mood lighting application running on a Bluetooth connected phone or tablet as an "event".

That said, if the micro:bit is being tilted by only 5 degrees or less, we'll do nothing. We assume the user doesn't want any change unless they tilt the micro:bit by more than this.

Add an If block after the code which obtains the current roll value. Set its condition to check that the value of the measured roll is at least 5 degrees either to the right or to the left. Tilting to the right will give us a positive roll value such as +10 degrees. Tilting to the left will produce a negative roll value such as -10 degrees. Since we don't care which direction the micro:bit is being tilted in for this check, we can ignore the sign and effectively treat negative numbers as if they were positive by using the "absolute" function. So "absolute(-10)", for example, produces +10. We could have used a logical OR instead and had a longer If condition which tested for roll being greater than +5 or less then -5.

Inside this new If block, add the long calculation, which determines the event value we need to send to the bitty mood lighting app over Bluetooth. This is a bit complicated so sit tight whilst I try to explain it.

Event value are 2 bytes long. In the first byte (the least significant part), we want to place a number which indicates the colour change amount. I'll explain more fully what this value is, shortly. In the other byte, we want to place our colour part value of 1, 2 or 3, for red, green or blue.

This code...

256 x colour

...shifts the value of our colour variable so that it occupies the most significant of our two bytes. To fill the least significant byte with the colour change amount, we just calculate it and add it to the result.

This code...

(roll - Math.abs(roll % 15)) / 15 + 7

...treats the quarter-circle which we can tilt the micro:bit in, from flat (0 degrees) to vertical (90 degrees) as being divided into 6 equal sized segments, each 15 degrees wide. It then generates a simple number indicating which of the 12 possible 15 degree segments the micro:bit has been tilted to. In short, the calculation tells us how much the micro:bit is being tilted by and in which direction. It generates the following possible values:

COLOUR_CHANGE_NEGATIVE_1 = 6;
COLOUR_CHANGE_NEGATIVE_2 = 5;
COLOUR_CHANGE_NEGATIVE_3 = 4;
COLOUR_CHANGE_NEGATIVE_4 = 3;
COLOUR_CHANGE_NEGATIVE_5 = 2;
COLOUR_CHANGE_NEGATIVE_6 = 1;

COLOUR_CHANGE_POSITIVE_1 = 7;
COLOUR_CHANGE_POSITIVE_2 = 8;
COLOUR_CHANGE_POSITIVE_3 = 9;
COLOUR_CHANGE_POSITIVE_4 = 10;
COLOUR_CHANGE_POSITIVE_5 = 11;
COLOUR_CHANGE_POSITIVE_6 = 12;

Negative change values indicate a tilt to the left. Positive values indicate a tilt to the right. Large values mean bitty mood lighting will make large changes to the current colour and small values mean it will make small changes.

Add a "Raise event" block to transmit the calculated event value over Bluetooth. Use a "source" of 9006 as shown.

The final version of your button B handler should now look like this:


step 11 - buttons A + B - standby / active mode

If buttons A and B are pressed at the same time, we need to switch to standby mode or active mode, depending on which state we're currently in.

Add a 3rd button handler block and set it to respond to buttons A+B. Add blocks to it until it looks exactly like the image below. This will cause the current standby/active mode indicator to be "toggled" (i.e. swapped) and an event sent to the bitty mood lighting app over Bluetooth to inform it of the change.

The final version of your button A+B handler should now look like this:


step 11 - final testing

You've now created the complete bitty mood lighting micro:bit code using PXT. This was a fairly challenging tutorial, so if you made it this far, well done!

You should now test your code carefully and fix any problems you find. Compile the PXT project and install the hex file. You'll need to forget any pairing details on your smartphone and go through the pairing process again (unfortunately!) but once you've done that you should be able to systematically test all the various ways in which your micro:bit can interact with the bitty mood lighting application. Good luck and enjoy having fun with bitty mood lighting!


if you get stuck

Take a close look at the solution here and watch the video showing the PXT project being created. Look for anywhere where your project is different. And don't forget, make sure you've paired your phone or tablet and micro:bit properly.