Creating an IoT LED matrix controlled by Storyblok
Storyblok is the first headless CMS that works for developers & marketers alike.
What if, instead of doing another Zoom call, we used IoT to connect to our team? What would happen if your remote team could change actual LEDs in your office? This blog post explains how to get started with LEDs & Storyblok. It includes the technical aspects of using Storyblok to control LEDs, as well as implementing a small Svelte component to create a simple interface, that is easy to interact with.
Parts
- ESP8266 wifi microcontroller (e.g. NodeMCU Lolin V3) ~6€
- LED matrix module (e.g. CJMCU-8x8 Modul) ~10€
- Capacitor (1000 µF), ~40cents
- Resistor (470 ohm), ~5cents
- Powerbank + Cable or a Battery, ~5-10€
- Female to female arduino jumper wires ~4€
- Solder Iron, ~12€
You have the microcontroller (ESP8266) that sends data to the LED matrix (green wire). In between the data line, you should include a small ~470-ohm resistor. Adding a resistor between your microcontroller's data pin and the data input on the LEDs can help prevent spikes on the data line that can damage your first pixel.
Then you have some power source, for example, a power bank or a battery, that can provide 5V. From the power source, you have two ground connections (black wire) to the microcontroller GND pin and the LED matrix GND pin.
You also need a power connection 5V (red wire) to the VIN pin of the microcontroller and the 5V PIN on the LEDs. When working with LEDs it's recommended to have a capacitor (1000 µF) between the GND and 5V connection to protect the LEDs. Before connecting LEDs to any large power source, add a capacitor across the GND and 5V connections. The capacitor buffers sudden changes in the current drawn by the strip.
I can recommend the Adafruit Neopixel Überguide to understand the basics of working with LEDs and microcontrollers.
Prototype Kit
The easiest way to get started is to use a breadboard to prototype what you want to do before doing any soldering. I bought a basic kit (~13€) that includes a breadboard, some resistors, buttons and cables to prototype. I still use the breadboard on any project I start, because it allows me to try things out without having to solder anything in the beginning.
USB Cable
I cut open an Ikea power cable I had lying around and created three power and ground connections from it. Don't forget to add some shrink tubes to the cables, so the GND and VIN connections do not touch each other. I soldered some female jumper wires together and then connected them to the USB cable. There are also some white/green data cables in a USB cable, which I just cut off and ignored. This was all the soldering I had to do.
Building the Box
For the box I decided to refurbish a Linzer Torte box I had gotten as a present at the ScriptConf conference, where I first met Storyblok. I measured the distances from the matrix, drilled some holes and painted the whole box black with acrylic color.
Finally, I attached the matrix to the top of the box with some tape and drilled a hole for the USB power cable in the bank to attach my large power bank. In the future, I want to get a small power bank that fits inside the box.
Code
Finally, we need to set up the environment to put our code on the microcontroller. I followed this basic tutorial to get the environment running. The first step is to install the Arduino IDE. Next, we need to add the correct board manager: Click on Arduino --> Preferences {1}, and at the bottom under "Additional Board Managers" {2}, enter the manager for your board. For my board it was https://arduino.esp8266.com/stable/package_esp8266com_index.json
Once you added the manager you need to go to Tools {1} --> Boards {2} --> Boards Manager {3}. Then search esp8266 and install the package, if it's not installed already.
Finally, select the correct board. Go to Tools {1} --> Board {2} --> ESP8266 Boards {3} --> NodeMCU 1.0 {4}
The last setup step is to install the necessary libraries we need. Go to Sketch --> Include Library --> Manage Libraries and install the following libraries: ESP8266WiFi , ESP8266HTTPClient , WiFiClient, ArduinoJson, and FastLED.
Let's add the different parts of our code, first we need to include all the libraries:
Then we need to define some basic variables, the LED_PIN is the number of our microcontroller data pin. We have an 8x8 matrix, so 64 LEDs. We're setting a fixed LED brightness of 64. Our LED type is a WS2812B, which is a very common type of LED. And the color order needs to be set according to the module you're using, for me it's CRB. Since our ESP8266 has a wifi module, we also need the settings of the wifi to connect to. Here is a basic example of how Wifi connections of the ESP8266 work.
Next we have some variables for calculating the matrix layout and the settings of the wifi to connect to. The calculations and variables I copied from the FastLed XY Matrix example. It allows you to calculate the x and y values of each pixel depending on the layout of the matrix.
The main parts of every Arduino project are the setup and the loop function. The setup function is the function that is called once, when the microcontroller is powering up. Here we set a short delay while it's powering up. Set the port for the Serial monitor to debug our code Serial.begin(115200)
. Read this tutorial to learn how Serial communication works. Basically we need to set the same baud rate in our Arduino IDE and on the controller to be able to display the Serial text. Finally, in the setup, we add our LED settings like the number of LEDs and the brightness and start our Wifi connection.
Finally, after the setup, we have the main loop
function, which loops consecutively, allowing your program to change and respond. We're using a lastTime
variable to throttle our behavior to only happen every 10 seconds. Once our Wifi is connected, we're creating an HTTP client, which then reads Storyblok's JSON endpoint. If the request was successful, we pass the response to the ArduinoJson library, which makes it easy to work with JSON on the microcontroller. They have a nice example of how to work with HTTP requests.
Once we parsed our response from Storyblok, we will iterate over all the elements in the story.content.body
and read the color
property, which will be a String hex code. We will then calculate the x and y value of the pixel on the matrix and pass that to a helper function together with the hex string we received from Storyblok colorLEDwithHex(x, y, hexCode)
.
The last part is our helper function, it takes the x and y values and the hex code. This function calculates r, g, b values out of the hex code and sets the color directly on the correct pixel by using our XY()
helper function.
And that's all the code we need on our microcontroller to color the LEDs.
Storyblok Setup
Of course, we still need our Storyblok setup to control the pixels. Create a new space, click on Content and open the Home story. There you should already have a body field of the type blocks set up. Click on the body, delete the teaser and grid and click Add block. Enter led {1} as a name and click Create new 'led' {2}.
Then for the led enter a new value {1} named color. Click on the new value {2} and as a Type, select Plugin. Then as a custom type select native-color-picker. Now click Save schema.
Finally, if you return to the base page entry, you should be able to add multiple LED blocks to the body {1}. For my matrix, I had to add 64 LEDs and I sent them all to #000, so initially, they are not colored. To make that easier, I created about 5 and then just copy and pasted multiple blocks.
You can also restrict the blocks on the body to only allow led components to be added by clicking Allow only specific components to be inserted on the body schema and selecting the LED component.
Frontend Interface with Svelte
To make this easier to interact with and to understand for my team, who didn't see the LED box live, I create a Svelte component. The component allowed you to select each pixel individually and showed all the current colors. I haven't worked with Svelte before but followed our 5-minute Svelte tutorial to set up the connection. I created a file storyblok.js
with the following four functions:
Conclusion
This project was really fun to build and it created some great interactions in my team, so I can totally recommend trying it out! I also learned a lot about using a headless system together with Arduino, which went pretty smoothly in my opinion. Here is a final video of what it looks like.
Resource | Link |
---|---|
Adafruit Neopixel Überguide | https://learn.adafruit.com/adafruit-neopixel-uberguide |
Arduino IDE | https://www.arduino.cc/en/software/ |
Arduino JSON | https://arduinojson.org/ |
Svelte | https://svelte.dev/ |