MakeCode Arcade is a free Microsoft block programming environment designed specifically to make games, but we can also use it for non-game application development. Learning to use MakeCode is easy & fun.
If you're not already familiar with the basics of MakeCode Arcade, check out this guide on creating a character sprite and moving it with controls.
To start, open a new Chrome browser window (Chrome works best) and go to MakeCode Arcade.
These MakeCode Arcade guides are designed to take you through the fundamentals before tackling more complex games -- even though this NeoPixel Strip Control isn't a game, most of the techniques apply:
For intermediate-level techniques, check out:
Start by launching MakeCode Arcade using the Google Chrome web browser. Then, download the led_strips_arcade-PyGamer-NeoPixel-Controller.png image cartridge file above by right-clicking on the image and saving it to your computer.
Load the Code
This is a special .png file that contains not only an image, but the entire game is embedded in it as well!
Simply drag it from the location to which you saved the image on your computer (such as the desktop as shown here) onto the Chrome browser window that is already running MakeCode Arcade (MCA). Note that the image in this graphic is of a different game, but you'll be dragging the Plantagotchi.png file.
This will open the code into the MCA editor.
We'll take a look now at how the application works. When you load it into MakeCode Arcade, the first thing you want to do is find the on start block and turn the debug variable to true. This allows us to run the program in the simulator window. Since the program connects to real, physical sensors, the simulator can't run the program until we disable some of the features with the debug switch.
NOTE: You can learn more about the idea of using a debug control switch here:
Here's what happens when we start up the program. First, we set background color to light blue. Then, we call the makeSprites function where we set up our plantSprite and the two icons for the corners of the screen, sunSprite and waterSprite.
My daughter designed the super-cute graphics. She drew them first on paper and then we worked together to translate them into pixel art!
We'll set up a couple of variables to use later, waterLevel and sunLevel.
The call counterSetup block runs the counterSetup function which uses the Seven Seg extension to place number readouts in the four corners of the screen.
This program makes use of some extensions to MakeCode Arcade: Feather, Controller, and SevenSeg.
Feather allows us to use the many digital and analog IO pins available on the PyBadge Feather header -- this is how we'll read the analog values of the soil moisture sensor.
Controller will allow us to use the on-board photocell light sensor.
SevenSeg gives us the ability to display numeric values on screen.
If you're starting from scratch, Head to Advanced > Extensions + and then click on those two extensions to add them to your session. If you're opening the provided .png image cartridge there's no need, they're already added to the session.
on start Continued
Continuing on with the on start block, we'll set the brightness level for the onboard NeoPixels to something pretty low, in this case 3.
Next is our debug variable, which we have set to a boolean false value. This can be flipped to true to use debug mode as mentioned above.
In fact, here's the first case of it that we'll see -- the if not debug conditional loop will only run the code contained within it if debug is true.
This is so that we can run the program in the simulator without making it throw an error message that it can't access the Feather analog A3 pin.
This line gives us the functionality we need to instantiate the A3 pin for analog reads:
let Analog03 = pins.A3.analogRead()
You can then switch back to Blocks mode by clicking the button at the top of the browser window.
Sprite Change Functions
You can think of the Plantagotchi as a machine that reads inputs for water levels and lights level, and then displays an appropriate set of graphics based on those readings. This set of functions is what we'll use to display the proper graphic.
For example, when the light level is 3 and the water level is 3, the default happy face will be displayed. By calling on the happyPlant function, the plantSprite image will change to the happy face, and the sunSprite and waterSprite icons will switch to their neutral state graphics.
The full set is:
We'll use this setSunLevel function to remap the raw light readings into five bands. The light level block is the raw reading from the on-board light sensor, 0-255 values.
I put the PyBadge in different lighting scenarios to determine the different ranges for five sunLevel settings. So, anything less than 16 is total darkness (since there's some light leak from the screen's backlight it doesn't go down to 0), 16-25 is moderate dark, 25-50 is normal daylight in the middle of a room, 50-245 is on a window sill, and higher than 245 is direct sunlight. You may need to tune these values yourself.
In a moment we'll look at how we use both the raw values and the remapped ranges, but first, let's look at the waterLevel function.
This works pretty much the same as the sunLevel function, except for reading the moisture sensor. One exception is that currently there isn't a block for
Again, I used some trial and error with very dry soil, moderately dry soil, average moisture soil, freshly watered soil, and overly wet soil to come up with practical value bands. The analog read values range from 0-1023, however my particular soil must have a lot of minerals in it, because even very dry soil was giving me a reading of nearly 800. Which is to say, your numbers may vary greatly depending on the dirt you use!
Do All the Things!
This is the block that does all the things! on game update every 1000ms will run every second and run through all of these steps:
- check the debug variable state to determine if the setSunLevel and setWaterLevel functions will be called, thus getting the current sensor values, as well as updating the SevenSeg counters with those raw values
- set the waterCounter and sunCounter to their respective remapped (1-5) values
Then, it will run through the big if...else if conditional block to determine which graphic set to display for the face and the two icons. For example, if sunLevel is greater than 3 and waterLevel is less than 3 the sunnyDryPlant function will be called, and we'll see those graphics appear. Probably time to water the plant and think about getting it out of the sun!
Buttons for Testing
When working with a project that uses sensors and displays graphics based on multiple possible conditions, it's useful to have a way to pretend each condition is being met to make sure the proper graphics show up (or whatever result you're expecting from each condition).
This is another way we'll use the debug mode. We've set up the d-pad buttons to increase and decrease the waterLevel and sunLevel values artificially! So, when debug is true, you can test the graphics in either the simulator or on the PyBadge after uploading the code just by pressing the buttons.
These have no function when you're out of debug mode and using the real sensor values.
NeoPixel Level Indicator
Since the PyBadge has a five NeoPixel strip built right onto it, it'd be a shame not to use it! Here, we'll use an on game update every 5000ms block to light up the NeoPixels with either the water level or light level every five seconds.
You can see how the ledMode variable is being used to flip flop back and forth between the two states every other five seconds.
Now, you can upload the code, connect up your probes to your potted plant, and try it out!