Introduction: Wordle Scoreboard

Make an LED scoreboard of your family's Wordle scores! This will cycle through your family's initials and then display their daily score as published to Twitter.

Supplies

LED Matrix with MAX7219 LED Driver

Particle Argon

Breadboard

Jumper wires

USB Cord

Twitter accounts

Step 1: Wiring

Depending on your LED matrix, you may need to solder wires to the matrix to connect to the Argon. If your matrix has the little metal things then you can just use jumper wires. Your Argon needs to be on a breadboard, and then you can place all wires next to their proper ports on the Argon. Connect the Argon to your computer power supply via the USB cord.

Step 2: Set Up Apify

Apify develops flexible and ready-to-use APIs for many different services. We'll be using one to scrape the Twitter website for the most recent Tweet by an account. Apify lets you create $5 free of API calls, so unless you're calling over 50,000 total Tweets, you shouldn't need to pay any money.

  • After creating an account, go to the store and select "Tweet Flash Twitter Scraper" by Jonathon Larson.
  • From Tweet Flash, create a New Task. Call it whatever you like.
  • Under the "Overall Maximum Tweets" field, select the number of people whose scores you intend to display.
  • Under "Scrape by Profile" add all the profile handles you intend to scrape.
  • IMPORTANT: Enable the "Experimental Profile Scraper"
  • Under "Filter Content" enable "Only tweets (no retweets, replies or quotes)."
  • At the bottom of the page, save your changes and start a new run.

Under "Runs" you should see the most recent tweet from your chosen profiles!

Step 3: Set Up Webhook

Now we're going to connect our Argon to Apify!

  • Login to the Particle Console at console.particle.io.
  • Go to the "Integrations" tab on the left side of the console.
  • Add a new integration. Select "Webhook."
  • Change the Name to "Wordle"
  • Change the Event Name to "scrape"
  • Go back to Apify. From your task click on the "API" button in the upper right corner.
  • Copy "Run task synchronously and get dataset items" to your clipboard.
  • On the Particle Console, change the Webhook's URL to the URL you copied.
  • Change the Request Type to "GET."
  • Create your webhook!

To test your webhook:

  • Go to the "Events" tab on the left side of the console.
  • Click on the green "Publish an event" button.
  • Set the event name to "scrape."
  • You should see the event "hook-sent/scraper" appear in the list.
  • Wait for 20-30 seconds.
  • If it returns "ESOCKETTIMEDOUT" once, wait for it to automatically try again. If it keeps timing out, close the tab and try again in a few minutes. If timeouts persist, then try lowering the number of overall maximum tweets you scrape. Depending on the day, each Tweet takes around 5-10 seconds to call, but Particle times out a Webhook event after 20 seconds. If you want to get around this then try creating individual tasks and Webhook events for each profile, then using Particle.publish("eventname"); for each event in the loop.

Step 4: Code!

  • Create a new project from the Particle Web IDE.
  • Add some code and save. If you don't do this, then the project will not be saved and you cannot progress to the next step.
  • Go to Libraries (The bookmark button)
  • Search for "ledmatrix" and "ledmatrix-max7219-max7221" and include it in your new project.
  • Also add the "ArduinoJson" library to your project.

Your project should now have this automatically generated code.

// This #include statement was automatically added by the Particle IDE.
#include <ArduinoJson.h>

// This #include statement was automatically added by the Particle IDE.
#include <ledmatrix-max7219-max7221.h>

Now under that, add this code. Read through the code and follow the instructions in the capital letters.

int arrayLength = 0;
int person = 0;
int yellows[60];


StaticJsonDocument<256> doc;
LEDMatrix *led;


//INCREASE THE NUMBER IN THE BRACKETS TO THE NUMBER OF PEOPLE WHOSE SCORES YOU WISH TO DISPLAY.
String scores[2];


void flashPixels()
{
    for(int i = 0; i < arrayLength; (i + 2))
    {
        led->drawPixel(yellows[i], yellows[i+1], true);
        led->flush();
    }

    delay(2000);

    for(int i = 0; i < arrayLength ; (i + 2))
    {
        led->drawPixel(yellows[i], yellows[i + 1], false);
        led->flush();
    }
}


void displayLetter()
{
    //ADD THE FIRST INITIAL OF YOUR FAMILY MEMBER'S NAMES TO THE ARRAY. THE ORDER SHOULD MATCH THE ORDER OF THE ACCOUNTS IN APIFY.
    char letterArray[] = {'J', 'C'};
    led->drawChar(0, 0, letterArray[person], true, false, 1);
    led->drawPixel(6, 1, true);
    led->drawPixel(6, 6, true);
    led->flush();
}


void displayScore(String tweet)
{
    int charCount= 0;
    for(int i = 0; i < tweet.length(); i++)
    {
        if(tweet.substring(i, i + 3).equals("⬜"))
        {
            charCount++;
            i = i+2;

        }


        else if (tweet.substring(i, i + 4).equals("🟩"))
        {
            led->drawPixel((charCount % 5), (charCount / 5), true);
            led->flush();
            charCount++;
            i = i+3;


        }
        else if (tweet.substring(i, i + 4).equals("🟨"))
        {
            yellows[arrayLength] = (charCount % 5);
            yellows[arrayLength + 1] = (charCount / 5);
            arrayLength = arrayLength + 2;
            charCount++;
            i = i+3;
        }
    }
    flashPixels();
    delay(2000);
    memset(yellows, 0, arrayLength);
    arrayLength = 0;
}


void setup() {
    Serial.begin(9600);
    led = new LEDMatrix(1, 1, A1, A2, A3);
    led->addMatrix(0, 0, 270);
    Particle.subscribe("hook-response/scrape/0", myHandler);
    Particle.publish("scrape");

    //CHANGE YOUR THE NUMBER TO THE OFFSET OF YOUR TIMEZONE FROM UTC.
    Time.zone(-6);
}


void loop() {
    displayLetter();
    displayScore(scores[person]);

    if(person == sizeof(scores))
    {
        person = 0;
    }
    else
    {
        person++;
    }

    if(Time.minute() == 30 || Time.minute() == 0)
    {
        Particle.publish("scrape");
    }
    if(Time.hour() == 0)
    {
        memset(yellows, 0, sizeof(yellows));
    }

}


//Gets webhook data and converts it to a String array.
void myHandler(const char *event, const char *data)
{
    const char* json = data;


    deserializeJson(doc, json);

    //IF YOU ARE CALLING MORE THAN TWO ACCOUNTS, THEN ADD ADDITIONAL const char* VARIABLES IN THIS FORMAT, INCREASING doc[n] FROM 1.

    const char* textZero = doc[0]["text"];
    const char* textOne = doc[1]["text"];

    //THEN, ADD TO YOUR SCORES ARRAY.
    scores[0] = String(textZero);
    scores[1] = String(textOne);
}