A few months ago I randomly came across a Facebook app for a little device that looked completely unnecessary yet also completely cool: Tidbyt. The Tidbyt is a little hardware LED device that shows different pieces of data, for example, sunrise and sunset:

Hardware showing sunrise/sunset

Or moon phase information:

Moon phase displayed on Tidbyt

And of course, Nyan cat:

Nyan cat on Tidbyt

As I said, this is not something I need in my life, but I'm so happy I got it. It's just a fun piece of hardware. But even cooler is that it's got an API. You can use the API to build full apps or just one-time messages. Their developer documentation is pretty well done, and while I ran into a hiccup or two, it was pretty easy to start sending custom messages to my hardware. The only real nit is that you must send a picture, a 64x32 image. That's kind of a bummer when you want to just send a quick text message, but there are multiple ways to generate images out there so it's not too much of a problem.

With that in mind - let me share how I built a Netlify integration!

What I'm Building #

Short and simple - when I deploy my site (this site, the one you are on right now!), I want a notification when the build is complete. Something like so:

Netlify takes between two to four minutes when building my site, so this way I can get a visual notification when the build is done. Let me share how I did it.

The Pipedream Workflow #

The main part of the process is a Pipedream workflow that uses an HTTP trigger. Essentially a simple serverless endpoint. Outside of the trigger is one code step. Now, here's where things got a bit complex. I knew I needed to generate an image with text. While I've done some work with Node libraries in the past to read and manipulate images, it's been a while since I had to use one. I also ran into an issue where the NPM modules I found didn't work well on Pipedream.

At first, I thought about using a placeholder image service. Many of them let you define an image with text on it, already centered, and while I struggled a bit, I did get something working there.

While chatting about this on the Pipedream slack, one of the members there recommended Bannerbear. This is a really cool image API service that has a very simple API. You design a base template using their web-based tools, and can then use an API to say, "Take this template, manipulate it, and return me the result."

Here's how I used it:

var data = {
    "template" : "V32jY9bBeN0DBGWrlo",
    "modifications" : [
    {
        "name" : "text_container_3",
        "text" : "Build Complete",
        "text_align_h":"center",
        "text_align_v":"center",
        "color" : "#FFFFFF",
    }
    ]
}

let resp = await fetch('https://sync.api.bannerbear.com/v2/images', {
    method: 'POST',
    body: JSON.stringify(data),
    headers: {
    'Content-Type' : 'application/json',
    'Authorization' : `Bearer ${process.env.BANNER_BEAR_API_KEY}`
    }
    });

let result = await resp.json();

As you can see, there isn't too much to it. I specify a template (which for me was just a black rectangle using the proper size for Tidbyt) and then the text I want to use. I send this to Bannerbear and the result is a JSON packet that includes the URL to the generated image. Now I want to be clear, Bannerbear has a heck of a lot of options, I just used the quickest and simplest thing I could to generate my image, but it's definitely a service to check out. Here's what that image looks like when done:

Build Complete

The next step was to get that data on my Tidbyt. As I mentioned, they have an API, but you can also find an NPM package: https://npm.io/package/tidbyt. Once installed, and with your keys setup in environment variables, it's pretty quick to use:

const tidbyt = new Tidbyt(process.env.TIDBYT_TOKEN);
const device = await tidbyt.devices.get(process.env.TIDBYT_DEVICE_ID);

let image = await fetch(result.image_url);
let img_data = await image.arrayBuffer();

await device.push(Buffer.from(img_data), {
    installationId:'Custom',
    background:false
});

Now... this was the first version and you probably noticed. I'm calling an API to generate a dynamic image... with static text. That's kind of dumb. So after I got it working, and sent Bannerbear a virtual high five, I stopped using their API and simply saved the image to my Pipedream workflow attachments. Now the code step is a bit simpler:

import Tidbyt from 'tidbyt';
import fs from 'fs';

export default defineComponent({
  async run({ steps, $ }) {
    
    const tidbyt = new Tidbyt(process.env.TIDBYT_TOKEN);
    const device = await tidbyt.devices.get(process.env.TIDBYT_DEVICE_ID);

    let img_data = fs.readFileSync(steps.trigger.context.attachments["build_complete.png"]);

    await device.push(Buffer.from(img_data), {
      installationId:'Custom',
      background:false
    });


  },
})

The Netlify Integration #

The final step was to copy the URL from the Pipedream workflow and tell Netlify to hit it on a successful build. I went into my site's settings, Build & deploy, Deploy notifications. I added a new notification and selected the "deploy succeeds" notification. Lastly, I just pasted in my URL from Pipedream:

Deploy notification

Wrap Up #

As I said, I really like the hardware, and there are a lot of apps you can use with it. The API is nicely done and I could do something a lot more complex, but for a quick integration test, this simple workflow worked well. Let me know if you pick up the device and what you think.