Published © CC0

Smart LED Matrix for Particle Photon

Drive a 8x32 LED dot matrix module with a particle photon to display real-time weather or messages sent via the Blynk app.

BeginnerFull instructions provided1 hour2,810
Smart LED Matrix for Particle Photon

Things used in this project

Hardware components

Particle Photon
MAX7219 Dot Matrix Module

Software apps and online services



Read more


8x32 LED Matrix

There are many of these 8x32 matrix displays on eBay and Amazon. Make sure you pick one that uses the MAX7219 IC. The matrix module has 5 pin outs: VCC, GND, DN, CS, CLK. Attach VCC and GND to the corresponding pins on your Photon board. Attach CLK to D1, CS to D2, and DN to D3.

Blynk App Setup

The Blynk app is configured with the terminal widget (on V1) and a button (on V2). The terminal widget is used to send text strings for display on the LED matrix. The button switches the LED matrix display between text messages and weather.

Settings for Terminal Widget

The terminal widget is set for V1 "virtual pin." The Photon firmware uses Blynk_Write to capture strings input on V1.

The Webhook

I used a simple webhook to get METAR data from a nearby weather station. You can replace "KOJC" in the below example with the ICAO code of your nearest weather station. Or, if you were motivated, use a better weather service and parse data for display.



Photon firmware for interfacing with Blynk and Particle webhooks to display real-time information. Makes use of the matrix library and scrolling text example from https://github.com/digitalwizards/SparkCore-LEDMatrix-MAX7219-MAX7221. And the Blynk library (blynk.cc).
// Simple LED Matrix Display with Blynk and Weather Integration 
// Uses 4x MAX7219 Dot Matrix Modules to display messages
// Make sure you add these two libraries using the Particle IDE

#include <ledmatrix-max7219-max7221.h>
#include <blynk.h>

char auth[] = "1234"; // Put your blynk token here

LEDMatrix *led;

int bitmapWidth = 8;   // 8 is default
int webcount = 60001;   // timer to run the weather webhook every 60 seconds

String text = "Hello World";   // default string for display
String text2 = "No Texts";  //  default string for Blynk texts
String text3 = "Getting Weather"; // default string for weather

int mode = 0;

int textLength = text.length();

// default position of the text is outside and then scrolls left
int textX = bitmapWidth;
int fontWidth = 5, space = 1;

void drawText(String s, int x)
  int y = 0;
  for(int i = 0; i < s.length(); i++) {
    // Adafruit_GFX method
    led->drawChar(x + i*(fontWidth+space), y, s[i], true, false, 1);

void setup() {
  Blynk.begin(auth);   // setup Blynk 
  // setup pins and library
  // 1 display per row, 1 display per column
  // optional pin settings - default: CLK = A0, CS = A1, D_OUT = A2
  // (pin settings is independent on HW SPI)
  led = new LEDMatrix(4, 1, D1, D2, D3); // my pins vary from the default
  // > add every matrix in the order in which they have been connected <
  // the first matrix in a row, the first matrix in a column
  // vertical orientation (-90°) and no mirroring - last three args optional
  // the Wangdd22 Matrix has 4 matrix elements, arranged side-by-side
  led->addMatrix(3, 0, 0, false, false);
  led->addMatrix(2, 0, 0, false, false);
  led->addMatrix(1, 0, 0, false, false);
  led->addMatrix(0, 0, 0, false, false);
  Particle.subscribe("hook-response/get_weather", gotWeatherData, MY_DEVICES);   // see particle.io tutorial on weather webhooks

// In the Blynk app, I used the Termianl widget on virtual pin V1 to send text messages for display.  
   String cmd = param[0].asStr();
   text2 = cmd;

// In the Blynk app, I used V2 as a button to toggle mode between weather and texts.
    mode = param.asInt();

// This collects data from my get_weather webhook, METAR data in my example.  See the photon tutorial on webhooks to get other data.  https://docs.particle.io/tutorials/integrations/webhooks/

void gotWeatherData(const char *name, const char *data) {
    text3 = String(data);

void loop() {

    if (webcount > 60000) {    // fetch data via the webhook only once a minute
        webcount = 0;

// pick which text string will be displayed
    if (mode == 0) {
        text = text3;
        textLength = text.length();
    if (mode == 1) {
        text = text2;
        textLength = text.length();
    webcount = webcount + 1;
  if(led != NULL) {
    drawText(text, textX--);
    // text animation is ending when the whole text is outside the bitmap
    if(textX < textLength*(fontWidth+space)*(-1)) {
      // set default text position
      textX = bitmapWidth;
      // show heart
      delay(333);   // 1000 is default
      // turn all pixels off (takes effect after led->flush())
    // draw text
    delay(125);   // 250 is default 
  // animations end
  else if (led != NULL) {
    // shutdown all displays
    // free memory
    delete led;
    led = NULL;




0 projects • 3 followers