How to build a control panel for your Particle-powered brewing projects

In this post, I’ll cover creating a custom PCB and cloud-based control panel for keeping tabs on my home brewing hobby.

Brandon Satrom article author avatarBrandon SatromMarch 27, 2019
How to build a control panel for your Particle-powered brewing projects

A few weeks ago, I detailed my process for upcycling a Photon-based project of mine—the Brew Buddy—to the new Particle Argon. I covered creating a new breadboard prototype, adding a few new features not in the Photon version, and the process of converting the firmware to work with the Argon.

In this post, I’ll cover the second half of the project: from prototype to PCB and cloud-based control panel. As with the first part of this project, I’ve been live-streaming all my work on this project over on Twitch, so if you want to watch the replays, or join me for future projects, head over to my page and give me a follow to get notified.

Designing a new PCB with Eagle and OSH park

Having the ability to breadboard a new project is amazing, but once I get everything working, I can’t wait to get rid of that rats nest of wires and replace them with a fancy, custom-designed Printed Circuit Board (PCB). My original Brew Buddy project saw several PCB revisions over its early life, so of course I had to spin another board for this Argon-based iteration.

Various iterations of the Brew Buddy board

Various iterations of the Brew Buddy custom PCB that I’ve used over the years.

Creating PCBs in Autodesk Eagle

There are a number of tools out there for designing PCBs, including free tools like KiCAD and high-end tools like Altium and OrCAD. I tend to do my PCB design in Autodesk Eagle. It’s a powerful tool with a bit of a learning curve (like all tools of its ilk), but once you get the hang of it, it makes the process of bringing your breadboard prototypes to life a fun and rewarding process.

Since I had an existing version of the PCB for my Photon-based project, my process here was a relatively straightforward one:

  • Replace the Photon with the Argon
  • Re-route the pins to the proper places on the Argon
  • Add an additional pin for the SD card chip-select on the Adafruit TFT breakout
  • Add the Piezo disc (and resistor)

When creating custom PCBs, you could etch your own with dangerous chemicals, or let fabrication pros handle the process at a fairly affordable price. For the digital design of the final PCB, there are two key assets you’ll create: a schematic, and a layout. The schematic is the logical design of the board and is meant to show where all of the electrical connections are made between components on the board. Here’s a before and after view of how my schematic changed for this project:

A side-by-side comparison of the Brew Buddy schematic.

The layout describes the physical placement of the components on your PCB. It’s coupled tightly to the logical, schematic design so that your connections are logically, valid, but the layout is where you place components and draw copper traces between them. Here’s a before and after view of the physical layout of the PCB:

A side-by-side comparison of the Brew Buddy layout

My new Brew Buddy PCB is larger, partly to accommodate the larger Argon, and also to make room for the new Piezo. I could have made it smaller, but then I wouldn’t have an excuse to spin another rev of the boards, now would I?

The most time-consuming aspect of the four-step migration was the first: moving from the Photon to the Argon required a re-mapping of every logical and physical connection. Eagle does have a Swap Part tool that makes this a bit easier, but in the spirit of being careful and thorough, I didn’t use it so that I could verify every connection.

All in all, this part of the process took me just a couple of hours. If you’re interested in watching how this process played out, I live streamed it on Twitch, and you can find the recording below.

Ordering PCBs from OSH Park

With the board design done, it was time to order PCBs. There are a bevy of great, online PCB fabs around these days, but one of my personal favorites is OSH Park. They are inexpensive, quick, and if you like the color purple, you’ll love their PCBs.

Ordering PCBs from OSH Park is simple. All you need to do is drag the Eagle `.brd` file onto the “Let’s get started” drop zone and OSH Park will read the file, generate the layer instructions and give you a price estimate. If you have a Zip file with Gerber files (a set of individual files that represent the layers in a fabricated PCB, and pronounced like the baby food) you can upload those as well.

OSH park also allows you to make your PCBs publicly available for others to consume and even order. Here’s mine for the Brew Buddy if you’d like to take a look for yourself.

Once I had my PCBs ordered, I passed the time waiting by working on my web-based control panel, which we’ll cover in the rest of this post. When the PCBs arrived a week or so later, I did live stream the assembly (often called PCBa) and testing, which you can check out below.

Building a web-based control panel with Azure IoT and electric io

For the “cloud” portion of this project, I wanted to build a control panel, not just a dashboard. I wanted to be able to move between brew monitoring states (brewing vs. fermenting) and trigger actions from the same interface where I would view charts, graphs and the current state of my app. With the Azure IoT Hub and a great open source project called electric io, I was able to do just that.

My electric io dashboard for Brew Buddy

The entire process consisted of the following steps:

  • Wire my project up to Azure IoT Hub
  • Configure Electric IO to display device data
  • Add MQTT to my Firmware to receive cloud-to-device messages from Azure
  • Configure electric IO to Send C2D Messages

The first step is covered extensively in our Docs on setting up an Azure IoT Hub integration with the Particle Device Cloud, so I won’t repeat them here. In addition, Paul DeCarlo from Microsoft covered the second step in a recent blog post, so I’m going to gloss over that section as well. Key and unique to this project are steps three and four, which enabled me to turn electric io from a dashboard, into a true control panel.

Using MQTT to listen for Azure IoT Hub Messages

The Particle Device Cloud to Azure IoT Hub integration gives you a quick, painless connection between your Particle Device and Azure. It allows you to use the Particle.publish API as you would in any other project, and pipe that data into Azure directly.

In order to add Azure to Device communication, we need to do a bit more in our firmware. The Azure IoT Hub supports two modes of direct integration with the IoT hub: a language SDK, or through direct implementation of pub/sub through MQTT or AMQP. For this project, I opted to use MQTT.

For Particle devices, there are two great MQTT libraries to choose from, MQTT for basic support, and MQTT-TLS when a secure, certificate-based MQTT connection is needed. Azure IoT Hub requires a secure connection, so I installed the MQTT-TLS library and included it in my project:

#include “MQTT-TLS.h”

To create a TLS-based connection, you also need a client certificate, which Microsoft provides in their SDKs. I grabbed the DigiCert Baltimore Root certificate from their GitHub repo, and created a new file called `certs/h` in my project, which I included right after the MQTT library include.

#include "certs/certs.h"

The next step is to declare a callback function for all MQTT inbound messages, and create an MQTT client. I created a forward declaration for the callback and configured the client URI and port based on the online docs. Be sure to replace the `{your hub name}` string with the name of your own Azure IoT Hub, which you can find in the Azure Portal for your account.

void mqttCB(char *topic, byte *payload, unsigned int length);
MQTT client("{your hub name}.azure-devices.net", 8883, mqttCB);

The next step is to connect to the Azure MQTT server when the project starts up. In the setup function, I enabled TLS and pass in the certificate I downloaded and created earlier. Then, I called the connect method with my deviceID (deviceID = System.deviceID();) and a username and password.

client.enableTls(certificates, sizeof(certificates));
client.connect(deviceID, "{your hub name}.azure-devices.net/" + deviceID, "SharedAccessSignature {your SAS Token here}");

In the case of the Azure IoT Hub, the username you provide should be your hub endpoint—like myhub.azure-devices.net—plus your Particle deviceID.

For the password, Azure requires that you provide a SharedAccessSignature, or SAS Token. You can generate these for your own hubs with the Azure device explorer, the Azure CLI or the Azure IoT Tools for VS Code, which is what I did. I was already in VSCode building my app with Particle Workbench, so it was easy!

The Azure IoT Hub VSCode extension in action

The next step is to check the isConnected method to determine if I successfully made an MQTT connection to the Azure IoT Hub. In either case, I added some Particle.publish calls so that I can double-check this from the console.

If I get a positive result, it’s time to set up a subscription. Azure IoT Hub provides two ways to receive communication on embedded devices, Direct Method calls (which always send a response) and Cloud-to-Device (or C2D) messages, which function more like fire-and-forget messages. I decided to use C2D messages. To receive these, the MQTT client needs to subscribe to the devices/{deviceID}/messages/devicebound/# topic filter.

if (client.isConnected())
{
  Particle.publish("mqtt/status", "connected");
  bool msgSubResult = client.subscribe("devices/" + deviceID + "/messages/devicebound/#", MQTT::QOS0);

  Particle.publish("mqtt/message-sub-result", msgSubResult ? "subscribed to hub messages" : "subscription failed");
}
else
{
  Particle.publish("mqtt/status", "failed");
}

With the subscription set up, the last step is to define the callback. On the electric io side, my plan was to send a payload to the device that contained at least a property named methodName, which would correspond to a brewing mode on the device, like “brew,” “ferment,” or “stop.” On the firmware side, that meant I needed to receive and parse the payload to extract the methodName. Thankfully, there’s a great JsonParserGenerator library for just this purpose.

void mqttCB(char *topic, byte *payload, unsigned int length)
{
  char pload[length + 1];
  memcpy(pload, payload, length);
  pload[length] = NULL;

  jsonParser.clear();
  jsonParser.addString(pload);

  if (jsonParser.parse())
  {
    String methodName = jsonParser.getReference().key("methodName").valueString();

    Particle.publish("mqtt/message-method", methodName);

    setBrewMode(methodName);
  }
}

This method takes the payload byte array, converts it to a character array, loads it into the jsonParser, and extracts the methodName from the payload before calling the setBrewMode function, which fires off a number of actions based on the mode string.

With MQTT in place, I was able to turn my electric io dashboard into a control panel!

Sending Messages from Electric IO to a Particle-powered project

Electric Io provides a Button type that makes it easy to call functions and send messages. Just select “button” in the Card Type dropdown and click “create.”

Creating a new button card in electric io

Once you’ve created a button, you’ll need to choose the call type. If calling a Direct method on an Azure IoT device, you’ll want to specify the methodName and an optional payload. For a message, which is what I used, there’s no methodName, but you’ll want to specify a payload. In the example below, I define a payload of {‘methodName’: ‘brew’} to tell my device to move into brewing mode.

Defining the button call type and payload

After saving button settings, the card will change into just a title and button. To test, I can just click away!

Triggering a C2D Message with electric io

And if everything was configured on the firmware side correctly, I’ll see my device respond to the inbound message from Azure IoT!

Brewing begins when the message is received!

What’s next?

As an endless tinkerer , I’ll never claim that a project is done, but I feel pretty good about where this project is in terms of being on new Particle hardware and leveraging a sweet, cloud-based control panel.

I suppose the next logical step is to brew some beer!

If you’re interested in seeing the nitty-gritty as I assembled my custom PCB and built out the Azure IoT Hub integration with MQTT, you can check out the live stream replays below. I stream my IoT builds on Mondays and Thursdays on Twitch, so be sure to follow and join me for more Particle-powered fun!