<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Brandon Satrom</title>
    <description>The latest articles on Forem by Brandon Satrom (@bsatrom).</description>
    <link>https://forem.com/bsatrom</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F134737%2F027b5c9c-4448-4ddc-9cf5-87e6d89c8f5b.jpeg</url>
      <title>Forem: Brandon Satrom</title>
      <link>https://forem.com/bsatrom</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bsatrom"/>
    <language>en</language>
    <item>
      <title>The Strings of Cellular IoT</title>
      <dc:creator>Brandon Satrom</dc:creator>
      <pubDate>Fri, 19 Feb 2021 00:00:00 +0000</pubDate>
      <link>https://forem.com/bsatrom/the-strings-of-cellular-iot-4heg</link>
      <guid>https://forem.com/bsatrom/the-strings-of-cellular-iot-4heg</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UJwYEtF9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/903aazk776ky0nog30py.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UJwYEtF9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/903aazk776ky0nog30py.jpeg" alt="Marionettes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Title Photo by &lt;a href="https://unsplash.com/@sagardani?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Sagar Dani&lt;/a&gt; on &lt;a href="https://unsplash.com"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I’ve spent the last decade of my career working on software and hardware tools for developers. Tools designed to foster collaboration, and lower the learning-curve of complex technologies so that teams and companies can solve problems faster. Every product I’ve worked on – from web UI tools and mobile app dev services, to developer-biased IoT tools – was created to help developers get something done, faster. And every product was focused on untangling all of the complexity associated with building solutions in that space.&lt;/p&gt;

&lt;p&gt;In the IoT, we have more than our share of complexity. We get all of the complexity of the software world, mixed-in with a healthy dose from the physical world around us.&lt;/p&gt;

&lt;p&gt;In cellular IoT, I like to refer to this complexity as “the strings of cellular IoT.” They are the things that developers often cannot control about building IoT solutions, or which exist by pure inertia. They are things that slow developers down, cut off choice, or provide unnecessary duplication of effort. They are things that lead us to search for alternatives that may be less than ideal, but which feel worth the tradeoff in our frantic efforts to reduce friction.&lt;/p&gt;

&lt;p&gt;And while there are many such strings in the cellular space, these are the ones I tend to see most often:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Difficult-to-program modems.&lt;/li&gt;
&lt;li&gt;
Developer Guardrails.&lt;/li&gt;
&lt;li&gt;
Device lifecycle management pitfalls.&lt;/li&gt;
&lt;li&gt;
Security not included.&lt;/li&gt;
&lt;li&gt;
The meandering path from prototype to scale.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Difficult-to-program modems
&lt;/h2&gt;

&lt;p&gt;If you’ve ever had to work directly with a cellular or Wi-Fi modem, you’re no doubt familiar with the &lt;a href="https://en.wikipedia.org/wiki/Hayes_command_set"&gt;Hayes command set&lt;/a&gt;. This command set – often referred to as the “AT command set” because many of the commands start with the string “AT” – was developed by Dennis Hayes in 1981 as a standard command set for interfacing with dial-up modems. It’s terse, and was created in a time when instruction sets were designed to save space. As a result, it’s about as developer-friendly as machine code.&lt;/p&gt;

&lt;p&gt;It’s also still in use on many modems, including most cellular IoT devices.&lt;/p&gt;

&lt;p&gt;For those unfamiliar with the AT command set, here’s a brief example of the commands needed to turn on a cellular IoT module, set its APN, configure an LTE band, and start scanning for towers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PiQ0h9Eh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blues.io/blog/images/at-commands.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PiQ0h9Eh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blues.io/blog/images/at-commands.png" alt="An example of AT commands for controlling a cellular IoT device."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For many developers, myself included, AT commands are cryptic and inaccessible. They are non-intuitive, and differ from one module to the next. It’s a painful way to add a connectivity module to your application, and yet it’s still the way of the modern world if you’re looking to integrate a cellular modem into your IoT solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Guardrails
&lt;/h2&gt;

&lt;p&gt;The challenge of working with cellular IoT modems is well-known, and solutions do exist to create developer-friendly abstractions on top. The problem is that these abstractions often come with guardrails that do too much, or too little, to help accelerate building a connected solution.&lt;/p&gt;

&lt;p&gt;Some vendors create narrow guardrails and abstract away the complexity into developer-friendly APIs. The problem is, they also force you to adopt their Host microcontroller, their RTOS, and even a particular programming language. As nice as it is to abstract away the AT command set, cutting off developer choice in the rest of the stack is a steep price to pay, in exchange.&lt;/p&gt;

&lt;p&gt;Other vendors give you wide guardrails. They sell you only a SIM or a piece of hardware that requires you to furnish your own SIM and plan. This approach has certainly brought down the cost of IoT and M2M data plans, but it swings too far into the other direction. Developers get cheaper connectivity, but are left to build up the rest of their solution stack themselves. As a result, the developer ends up with the equivalent of “writer’s block” or “blank page syndrome” because there is so much to choose.&lt;/p&gt;

&lt;p&gt;The either-or nature of the guardrails in place today leaves developers with a difficult selection: accept too much restriction, or forge ahead with too little guidance?&lt;/p&gt;

&lt;h2&gt;
  
  
  Device lifecycle management pitfalls
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;How do you design a real world IoT device when the cost model isn’t built to account for real world use?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Beyond cryptic interfaces and guardrails, developers must also contend with the cost of managing devices and data, much of which is hidden from view. Every device has a price, but some have multiple: the price you pay up-front, the price you pay for data, and the price you pay for a device to change its state, for instance when activated or deactivated.&lt;/p&gt;

&lt;p&gt;When a device has multiple price components, or shadow costs, it can be hard to know exactly what your IoT solution is going to cost you. Especially since the reality is that IoT products don’t follow a happy path where they fly off the shelf, are deployed into the field immediately, and are used forever and ever without end.&lt;/p&gt;

&lt;p&gt;Instead, most IoT devices tend to go through a pretty consistent lifecycle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A inventory and distribution stage where they sit idle.&lt;/li&gt;
&lt;li&gt;Activation when they are first used.&lt;/li&gt;
&lt;li&gt;A period where they fall into less than regular use, but the device is still “online” and accruing fees.&lt;/li&gt;
&lt;li&gt;A period of temporary breakage, and it can often take months before the issue is identified and fixed.&lt;/li&gt;
&lt;li&gt;Re-commissioning after the device is fixed.&lt;/li&gt;
&lt;li&gt;A period where the device is decommissioned permanently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uoavX5pK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blues.io/blog/images/device-lifecycle.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uoavX5pK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blues.io/blog/images/device-lifecycle.png" alt="An illustration of a typical device lifecycle."&gt;&lt;/a&gt;&lt;br&gt;
            &lt;p&gt;The typical device lifecycle&lt;/p&gt;

 &lt;/p&gt;

&lt;p&gt;Now imagine that, for every one of these stages, you’re paying the same monthly data fee, regardless of actual use, as well as charges for activation, re-commissioning, and decommissioning. The challenge in the cellular IoT space is that each of these phases in the device lifecycle come with carrier fees and transaction costs that can be difficult to plan and budget for. As a result, when most developers look at an IoT device, they don’t know what its true cost is.&lt;/p&gt;

&lt;p&gt;How do you design a real world IoT device when the cost model isn’t built to account for real world use?&lt;/p&gt;

&lt;h2&gt;
  
  
  Security not included
&lt;/h2&gt;

&lt;p&gt;There’s also the string of security, a topic that developers are ever conscious of, but which many providers don’t bake into their products. Key and certificate management is an essential part of every IoT solution. And with all major IoT cloud services now requiring TLS, in the absence of baked-in security, developers are forced to store keys and certificates in firmware in order to connect their devices to cloud services.&lt;/p&gt;

&lt;p&gt;With keys and certs in firmware, your IoT devices become yet another sensitive vector that an attacker can use to get the (literal) keys to your kingdom.&lt;/p&gt;

&lt;h2&gt;
  
  
  The meandering path from prototype to scale
&lt;/h2&gt;

&lt;p&gt;Finally, there’s the string of the disconnect between prototype and production solutions, even as developer-friendly tools abound. As developers, we should consider ourselves fortunate that prototyping is as accessible as it is today, thanks to companies like Arduino, Adafruit, SparkFun, and the Raspberry Pi Foundation. But because much attention has been paid to how “maker friendly” these devices are, they are often dismissed as not production ready. IoT engineers will gladly use these accessible tools to prove an idea at the prototype stage, but throw those prototypes away and start over when it comes time to build a “real” solution.&lt;/p&gt;

&lt;p&gt;But if these tools are good enough for the &lt;a href="https://spectrum.ieee.org/automaton/aerospace/robotic-exploration/nasa-designed-perseverance-helicopter-rover-fly-autonomously-mars"&gt;Mars Ingenuity helicopter&lt;/a&gt;, they should be good enough for our solutions. And IoT solution vendors can absolutely do more to minimize the throwaway mindset with tools that make prototyping easy from the start, and which level-up to pilot and production scale just as seamlessly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complexity Kills
&lt;/h2&gt;

&lt;p&gt;When taken together, the strings of cellular IoT create a developer-hostile environment where complexity rules. From the start, the path of selecting a board to building a prototype to deploying and scaling a pilot is filled with hurdles and roadblocks that make it hard for many initiatives to succeed.&lt;/p&gt;

&lt;p&gt;When I think about complexity, I think of a quote from our Founder and CEO, Ray Ozzie. It’s something that he said long before setting out to start Blues Wireless, but which applies very much to the IoT of the present.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Complexity kills. It sucks the life out of developers, it makes products difficult to plan, build, and test. - Ray Ozzie&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introducing the Notecard
&lt;/h2&gt;

&lt;p&gt;It should come as no surprise that Ray was motivated to start Blues Wireless after &lt;a href="https://blues.io/blog/soul-of-a-new-machine/"&gt;experiencing the pain&lt;/a&gt; and complexity of building an IoT solution himself. As Ray detailed in his &lt;a href="https://blues.io/blog/soul-of-a-new-machine/"&gt;recent post&lt;/a&gt;, that journey started with the Fukushima Daiichi nuclear disaster and led to the Notecard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FeQgOSxa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blues.io/blog/images/notecard.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FeQgOSxa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blues.io/blog/images/notecard.png" alt="Close-up photo of the Notecard."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Notecard is a developer-friendly, production-ready cellular IoT device. It was built by developers, for developers, to address every one of the strings of cellular IoT. The Notecard:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is easy to program, with a built-in developer-friendly API.&lt;/li&gt;
&lt;li&gt;Let’s you set your own guardrails with your own host MCU or SBC.&lt;/li&gt;
&lt;li&gt;Has no hidden fees, and a built-in 10-year data plan (with no fees) bundled into the cost of the device.&lt;/li&gt;
&lt;li&gt;Includes baked-in keys and a secure connection to our &lt;a href="http://notehub.io"&gt;Notehub.io&lt;/a&gt; cloud service.&lt;/li&gt;
&lt;li&gt;And is built on a form-factor that’s ready to move to a pilot or deployment in a snap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Notecard is an uncomplicated cellular IoT device. It comes with 500 MB of data and a ten-year plan built-in, and starts at $49. If you’re evaluating cellular IoT solutions, you should check it out, and you can learn more at &lt;a href="https://blues.io"&gt;blues.io&lt;/a&gt;, our &lt;a href="https://dev.blues.io"&gt;Developer Portal&lt;/a&gt;, or our &lt;a href="https://shop.blues.io"&gt;Shop&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With the Notecard, we aim to cut the strings of cellular and allow the next generation of IoT solutions to be truly wireless.&lt;/p&gt;

</description>
      <category>iot</category>
      <category>development</category>
      <category>writing</category>
    </item>
    <item>
      <title>Learn about mesh networking by building this swarm of Particle-powered robots</title>
      <dc:creator>Brandon Satrom</dc:creator>
      <pubDate>Mon, 08 Jul 2019 20:32:15 +0000</pubDate>
      <link>https://forem.com/particle/learn-about-mesh-networking-by-building-this-swarm-of-particle-powered-robots-4c2j</link>
      <guid>https://forem.com/particle/learn-about-mesh-networking-by-building-this-swarm-of-particle-powered-robots-4c2j</guid>
      <description>&lt;p&gt;Hacking a toy is a fun form of electronics exploration. It’s a great way learn how real-world products are designed and built, and tinker without worrying about rendering expensive electronics useless in the pursuit of knowledge. Inexpensive consumer electronics are a fantastic platform for learning, exploration, and even building new, innovative solutions.&lt;/p&gt;

&lt;p&gt;Remote-controlled (RC) vehicles are a common target for makers, and cars with the “Thunder Tumbler” name provide a cheap, accessible platform for RC car hacking. The Tumbler has been hacked a number of times before, but I don’t think it’s ever been used in a mesh network. That is, until now. Using a couple of Tumblers that you can find online or in stores like CVS, and a few of Particle’s new, mesh-ready hardware, I created a swarmbot network of Tumblers that move in synchronized fashion at my every command!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post originally appeared in &lt;em&gt;Make: Magazine, volume 68&lt;/em&gt; and online &lt;a href="https://makezine.com/projects/diy-swarmbots/"&gt;here&lt;/a&gt;. It is reprinted here with the author’s permission. |&lt;/p&gt;

&lt;h2&gt;
  
  
  Materials needed
&lt;/h2&gt;

&lt;p&gt;For this project, you’ll need the following items:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(2-3) “Thunder Tumbler” RC Cars, available at many chain drug stores or online — here in the states both &lt;a href="https://www.walgreens.com/store/c/thunder-tumbler-radio-control-360-degree-rally-car/ID=prod6090850-product"&gt;Walgreens&lt;/a&gt; and &lt;a href="https://www.cvs.com/shop/blue-hat-thunder-tumbler-radio-control-rally-car-prodid-458767"&gt;CVS&lt;/a&gt; carry these cars. Note there are multiple versions of this product, but I’ll cover how you can handle these subtle variations.&lt;/li&gt;
&lt;li&gt;(1) &lt;a href="https://store.particle.io/products/argon-kit"&gt;Particle Argon&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(3) &lt;a href="https://store.particle.io/products/xenon-kit"&gt;Particle Xenons&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(3) breadboards — included with the Argon and Xenon kits&lt;/li&gt;
&lt;li&gt;Assorted jumper wires for connecting each Xenon to the RC Car’s PCB&lt;/li&gt;
&lt;li&gt;A multimeter for inspecting IC pin functions (as the pinout may vary from one cheap RC car to the next)&lt;/li&gt;
&lt;li&gt;Soldering iron and solder&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How does mesh networking work?
&lt;/h2&gt;

&lt;p&gt;Most connected solutions tend to rely on Wi-Fi or cellular for connectivity. This typically means that each connected device maintains a direct connection to the Internet. While this is useful for connecting to the cloud for data storage or processing, some connected solutions need to be able to operate on a local network, with other devices, regardless of whether a connection to the Internet exists.&lt;/p&gt;

&lt;p&gt;Mesh networking solutions enable these scenarios by allowing developers to create local networks of connected devices. The bulk of the network consists of endpoints that sense or actuate, and repeaters that help increase the size and reliability of the mesh by passing messages between devices. In addition, a small number of devices — often just one — serve as gateways to maintain a connection to the Internet. Critically, these local networks of devices can still communicate with one another when the connection to the network disappears. The &lt;a href="https://store.particle.io/"&gt;Argon, Boron, and Xenon&lt;/a&gt; — all 3rd generation Particle devices — provide built-in mesh-networking capabilities.&lt;/p&gt;

&lt;p&gt;For this build, I used mesh to create a network of RC cars, each controlled by a Particle Xenon. All of the Xenon RC cars are endpoints, and are connected to a mesh network with a single Particle Argon as the gateway. Once the network is established, I can use local network messaging to send low-latency commands to nodes on the network and make my RC cars dance.&lt;/p&gt;

&lt;p&gt;First, however, I needed to hack the off-the-shelf Tumblers to Particle-power them!&lt;/p&gt;

&lt;h2&gt;
  
  
  Hacking the Thunder Tumbler
&lt;/h2&gt;

&lt;p&gt;The first step of this process is hacking the RC car to add a Xenon. Regardless of the brand or style of RC car you’re using, the objective is to crack open the car to reveal the PCB inside, determine how the device sends commands to the motors to rotate the wheels, and connect pins from the Xenon to the corresponding motor driver pins on the car. Because these cars are inexpensive, you should expect to find some variation, even among those with the “Thunder Tumbler” name on the box.&lt;/p&gt;

&lt;p&gt;Write-ups on Tumbler hacking can be found online going back over 9 years. That’s a lifetime in the electronics world, so be sure to test and verify the functionality of your own cars as you follow-along with the instructions below.&lt;/p&gt;

&lt;p&gt;I suggest grabbing your favorite multi-meter and measuring voltages across various pins on the RC car PCB as you make the wheels spin with the remote control. Make sure to set your car somewhere where the wheels can rotate freely so that it doesn’t get away from you during testing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i_Z_K0Ls--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/tumbler-with-mm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i_Z_K0Ls--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/tumbler-with-mm.jpg" alt="Image of an R/C car and my multimeter."&gt;&lt;/a&gt;R/C Tumbler with my trusty multimeter. Since these cars are inexpensive, a multimeter comes in handy to reverse engineer the IC pinouts.&lt;/p&gt;

&lt;p&gt;Remove the two screws that hold the shell of the tumbler in place. Once these are out, you can lift the shell to expose the tumbler PCB. Inside, you should see 8-10 wires that run from the the car to the PCB, and a number of through-hole and surface-mount components.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I1696ocP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/Hbridge-hacking.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I1696ocP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/Hbridge-hacking.jpg" alt="Close up image of the H-bridge motor controller from the Tumbler. Using my multimeter, I was able to determine what pins control the motor."&gt;&lt;/a&gt;The Tumbler uses a classic motor controller designed known as an H-bridge driver. By testing the pads with my multimeter, I was able to reverse engineer what combination drives the car forward and backward, plus left and right steering. Note that some Tumblers use a different pinout than mine, so you’ll want to have a meter nearby to test your car.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the various onboard ICs
&lt;/h2&gt;

&lt;p&gt;The small surface-mount component on the top is a remote-controller receiver chip, the RX-2B. Its pair, the TX-2B transceiver chip sits in the remote control that ships with these cars. These ICs are commonly used for RC vehicles, and I was able to find their data sheets online to determine which pins map to forward, backward, left and right commands from the remote. I also used the data sheet to establish a known ground pin, which is needed to determine which pins power the car motors and can be controlled by a Xenon.&lt;/p&gt;

&lt;p&gt;This ended up being critical because the main IC on these boards, through-hole mounted on the bottom of the car PCB, is one for which I couldn’t find a data sheet, in spite of many hours of searching. While I’m still not 100% certain of all the features on this chip, it functions primarily as an H-Bridge motor controller. Pulsing a signal into a certain pin on the IC results in a pulse out to one of the motor control pins, which makes a wheel spin forward or backwards.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--atNMGv1t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/Hbridge-hacking-2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--atNMGv1t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/Hbridge-hacking-2.jpg" alt="Image of inserting the motor controller back into the Tumbler chassis."&gt;&lt;/a&gt;Inserting the motor controller back into the Tumbler chassis.&lt;/p&gt;

&lt;p&gt;By reverse-engineering, I was able to find that there are four pins I care about on this unknown IC: one that spins the left wheel forward, one that spins it back; one that spins the right wheel forward, and one that spins the right wheel back. I soldered one wire to the top of each of these pins, and one to a ground pin. Even though the Xenon and car are powered separately, they need to share a ground signal for everything to work, as needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a mesh network
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bhYxJyyT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/Fig-E-2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bhYxJyyT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/Fig-E-2.jpg" alt="Image of three screen shots from the mobile set up of a Particle Mesh network."&gt;&lt;/a&gt;Setting up a Particle Mesh network is a quick process with the Particle mobile app.&lt;/p&gt;

&lt;p&gt;Because this project requires a mesh network, you’ll want to set one up with one gateway (a Particle Argon or Boron) and one Xenon-based node for each RC car. If you want to program each Xenon over-the-air without having to connect each to a computer, you’ll want to set up your network in advance. You can do this from the Particle mobile app, or follow the instructions &lt;a href="http://Particle.io/start"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5YBlP4lb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/Fig-E-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5YBlP4lb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/Fig-E-1.jpg" alt="Three images from the Particle mobile app. Each shows a different stage in the mesh network setup."&gt;&lt;/a&gt;This image shows mobile flow you will go through when setting up a new Particle Mesh device.&lt;/p&gt;

&lt;h2&gt;
  
  
  Programming the tumblers
&lt;/h2&gt;

&lt;p&gt;Once you have your first Xenon claimed and ready, the next step is to write firmware for controlling the actions of each car. Since the goal is to create a small mesh of swarmbots, you’re going to create a simple sequence that moves the car forward, back, left and right. The code for this sequence can be found below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Wheel pin mappings
int leftReverse = A0;
int leftForward = A1;
int rightForward = A2;
int rightReverse = A3;

// Speed and delay variables
int speed = 85;
int turnSpeed = 255;
int forwardDelay = 1000;
int backDelay = 1000;
int turnDelay = 2000;

void setup()
{
  // Set motor pins to outputs
  pinMode(leftReverse, OUTPUT);
  pinMode(leftForward, OUTPUT);
  pinMode(rightForward, OUTPUT);
  pinMode(rightReverse, OUTPUT);

  // Make sure each motor is off
  digitalWrite(leftReverse, LOW);
  digitalWrite(leftForward, LOW);
  digitalWrite(rightForward, LOW);
  digitalWrite(rightReverse, LOW);
}

void runDemo(const char *event, const char *data)
{
  allOff();

  goForward(speed);
  delay(forwardDelay);

  goBack(speed);
  delay(backDelay);

  // Max spin to raise up on the back tires
  turnLeft(turnSpeed);
  delay(turnDelay);

  allOff();
}

void allOff()
{
  analogWrite(leftReverse, 0);
  analogWrite(leftForward, 0);
  analogWrite(rightForward, 0);
  analogWrite(rightReverse, 0);

  delay(50);
}

void goForward(int speed)
{
  allOff();

  analogWrite(rightForward, speed);
  analogWrite(leftForward, speed);
}

void goBack(int speed)
{
  allOff();

  analogWrite(rightReverse, speed);
  analogWrite(leftReverse, speed);
}

void turnLeft(int speed)
{
  allOff();

  analogWrite(rightForward, speed);
}

void turnRight(int speed)
{
  allOff();

  analogWrite(leftForward, speed);
}

void loop()
{
  // Nothing needed here. 
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You probably noticed that the meat of the demo is &lt;code&gt;analogWrite&lt;/code&gt; commands to turn each wheel forward or backward by sending a voltage to a corresponding pin. Through testing, I determined that the cars I’m using are PWM-able, meaning that I can set a wheel pin to lower than digital HIGH (3.3 volts in the case of the Xenon) and have the wheel turn at lower speeds. Notice that I’m passing in different values for turning right or left vs forward and back. PWM enables pretty complex patterns and speeds for these inexpensive cars.&lt;/p&gt;

&lt;p&gt;With the demo code done, the final piece you need on your RC cars is a subscription to a local network message that specifies the &lt;code&gt;runDemo&lt;/code&gt; function as the handler. Particle enables local, in-mesh-network messaging between nodes on a network using a &lt;code&gt;Mesh.publish&lt;/code&gt; and &lt;code&gt;Mesh.subscribe&lt;/code&gt; API. &lt;code&gt;Mesh.publish&lt;/code&gt; sends a broadcast message (with a name and payload) to all nodes on the network. &lt;code&gt;Mesh.subscribe&lt;/code&gt;, on the other hand, listens for messages (by name) and specifies a handler to process and respond to those incoming messages.&lt;/p&gt;

&lt;p&gt;Our Xenons will use &lt;code&gt;Mesh.subscribe&lt;/code&gt; to listen for a network message, and then trigger the demo sequence.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Add to setup functionMesh.subscribe("run-demo", runDemo);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Flash the completed code to each RC car Xenon and you’re ready for the final piece: programming the gateway to coordinate the movements of the car swarm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Programming the mesh gateway
&lt;/h2&gt;

&lt;p&gt;The mesh gateway is less complex than the code that runs on each Xenon, but still needs two pieces for the purposes of our demo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;a &lt;code&gt;Mesh.publish&lt;/code&gt; call to trigger the RC car demo sequence and&lt;/li&gt;
&lt;li&gt;a way to tell the controller to fire the message to the mesh network.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We could skip the second step by just firing the message when the gateway comes online, or regularly on a delay, but what fun would that be? Instead, we can use another Particle API Particle.function, to allow us to trigger the cars from a mobile phone.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void setup() {
  Particle.function("runDemo", runDemo);
}

int runDemo (String command)
{
  Mesh.publish("run-demo", NULL);

  return 1;
}

void loop() {
  // Nothing needed here
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Particle.function&lt;/code&gt; takes a string value name of the function (used when calling that function from a mobile or web app or through the cloud) and a handler function to execute when called. That function contains our &lt;code&gt;Mesh.publish&lt;/code&gt; call, which sends a broadcast message with the name “run-demo” to all listeners (i.e. our RC cars) on the network. Once you’ve added the code above to your gateway, you’re ready to control some swarmbots!&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it all together
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GOpG6tsV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/runDemoConsole.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GOpG6tsV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/runDemoConsole.jpg" alt="Screenshot of the Particle Console."&gt;&lt;/a&gt;Once you’ve built your RC cars and have them configured in a mesh network, you’ll be able to control them from the Particle Console.&lt;/p&gt;

&lt;p&gt;Particle functions can be called from any device that has a secure connection to the &lt;a href="https://www.particle.io/device-cloud"&gt;Particle Device Cloud&lt;/a&gt;, which could be the &lt;a href="https://console.particle.io/devices"&gt;Particle Console&lt;/a&gt;, the CLI, or even your own applications. They can also be called from the Particle mobile app, which seems like a fitting place to finish this project. The Particle mobile app shows a listing of every Particle device you own. Click on your gateway, then the “Data” tab menu, and you should see a “runDemo” function. Put your Xenons in position with plenty of space, and click the function to trigger some RC swarming!&lt;/p&gt;

&lt;p&gt;The demo code above illustrated a simple, coordinated sequence of actions. But with PWM and a bit of trial and error, there are a number of cool synchronized dances you can create with mesh-networked RC cars.&lt;/p&gt;

&lt;h2&gt;
  
  
  Command your swarm!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xqxhDuQ3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/RCdanceoff.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xqxhDuQ3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/RCdanceoff.jpg" alt="Three RC Tumblers on their back wheels. The image highlights the coordinated control you'll have thanks to the mesh network."&gt;&lt;/a&gt;With the project complete, it’s time for an RC Tumbler dance party!&lt;/p&gt;

&lt;p&gt;Now that your bots are meshed, let’s turn them into real swarmbots that can communicate with each other. A common swarm scenario is the leader-follower pattern. The leader determines movements for the swarm, and communicates these directly to all followers. One example would be to control the leader with the out-of-box remote control, read pin voltages off the leader car, and send these as instructions to all followers listening for a Mesh event.&lt;/p&gt;

&lt;p&gt;To build this demo, I designated one of my three cars as a leader, and added firmware to control the fleet. Instead of writing to my motor pins, the leader simply reads the analog values sent by the remote control and sends these to listeners on the network with a &lt;code&gt;Mesh.publish&lt;/code&gt; that includes the wheel, direction and analog value to apply to follower cars.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int32_t lastLeftRVal = 0;
int32_t lastLeftFVal = 0;
int32_t lastRightRVal = 0;
int32_t lastRightFVal = 0;

#define MIN_PIN_VAL 150
#define DRIVE_VAL 200

void setup()
{
  pinMode(leftReverse, INPUT);
  pinMode(leftForward, INPUT);
  pinMode(rightForward, INPUT);
  pinMode(rightReverse, INPUT);
}

void loop()
{
  checkPin(leftReverse, &amp;amp;lastLeftRVal, "leftR");
  checkPin(leftForward, &amp;amp;lastLeftFVal, "leftF");
  checkPin(rightReverse, &amp;amp;lastRightRVal, "rightR");
  checkPin(rightForward, &amp;amp;lastRightFVal, "rightF");
}

void checkPin(int pin, int32_t *lastVal, const char *event)
{
  int32_t pinVal = analogRead(pin) / 16;

  if (pinVal &amp;gt; MIN_PIN_VAL)
    pinVal = DRIVE_VAL;
  else
    pinVal = 0;

  if (pinVal != *lastVal &amp;amp;&amp;amp; pinVal == DRIVE_VAL)

    *lastVal = pinVal;

    Mesh.publish(event, String(DRIVE_VAL));
  } else if (pinVal == 0 &amp;amp;&amp;amp; *lastVal != 0) {
    *lastVal = 0;

    Mesh.publish(event, String(0));

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Code for the follower robots
&lt;/h2&gt;

&lt;p&gt;On the follower side, I added firmware that listens for a Mesh event for each pin, and performs an &lt;code&gt;analogWrite&lt;/code&gt; with the passed-in value. On the cars themselves, I also removed the antenna on each board and cut the traces from the remote RX IC just to make sure that movement commands were only coming from the leader.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void setup()
{
  pinMode(leftReverse, OUTPUT);
  pinMode(leftForward, OUTPUT);
  pinMode(rightForward, OUTPUT);
  pinMode(rightReverse, OUTPUT);

  digitalWrite(leftReverse, LOW);
  digitalWrite(leftForward, LOW);
  digitalWrite(rightForward, LOW);
  digitalWrite(rightReverse, LOW);

  Mesh.subscribe("leftR", leftR);
  Mesh.subscribe("leftF", leftF);
  Mesh.subscribe("rightR", rightR);
  Mesh.subscribe("rightF", rightF);
}

void leftR(const char *event, const char *data)
{
  move(leftReverse, data);
}

void leftF(const char *event, const char *data)
{
  move(leftForward, data);
}

void rightR(const char *event, const char *data)
{
  move(rightReverse, data);
}

void rightF(const char *event, const char *data)
{
  move(rightForward, data);
}

void move(int pin, const char *speed)
{
  int32_t speedVal = atoi(speed);

  if (speedVal &amp;gt; 16) // Filter out noise from the leader
  {
    analogWrite(pin, speedVal);
  }
  else
  {
    analogWrite(pin, 0);
  }
}

void loop() {} 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With this simple R/C-controlled swarm as our foundation, we built a bunch more swarm sequences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow the leader — basic forward and back demo with ending spin️&lt;/li&gt;
&lt;li&gt;Splinter — cars separate in three different directions and come back together&lt;/li&gt;
&lt;li&gt;Follow the leader and push — leader tells followers to stop, goes forward 2 seconds, turns around, goes back 2 seconds, then tells followers to move backward as it keeps moving forward&lt;/li&gt;
&lt;li&gt;Sentry mode — square path with right-angle turns&lt;/li&gt;
&lt;li&gt;Orbit — followers orbit a stationary leader.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can grab the complete project source code, including these more complex demos, from the repository on &lt;a href="https://github.com/particle-iot/mesh-rc-carsgithub.com/particle-iot/mesh-rc-cars"&gt;Gihub&lt;/a&gt;. I’ve also done a number of Twitch streams focused on building the demos for this project; check them out on my &lt;a href="https://www.twitch.tv/brandonsatrom"&gt;Twitch channel&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hack It and Share It
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nHxNAgi---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/RChero.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nHxNAgi---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/07/RChero.jpg" alt=""&gt;&lt;/a&gt;Ready to rule the world with my new RC Tumbler swarm robots.&lt;/p&gt;

&lt;p&gt;We’d love to see makers extend and modify this project with sensors and new behaviors. You could add collision detection to the leader with a PIR or ultrasonic sensor, or even use the remote to log predefined sequences that could then be repeated automatically. And if you’ve built your own mesh-style swarmbot project, or anything else with Particle’s new hardware, we’d love to hear from you! Share with us on &lt;a href="https://twitter.com/particle"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.instagram.com/particle_iot/"&gt;Instagram&lt;/a&gt;, or in &lt;a href="https://community.particle.io/"&gt;our community of 160,000 developers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Swarm on, makers!&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://blog.particle.io/2019/07/08/mesh-networking-swarm-robots/"&gt;Learn about mesh networking by building this swarm of Particle-powered robots&lt;/a&gt; appeared first on &lt;a href="https://blog.particle.io"&gt;Particle Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>showdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Get up to speed with Particle Variable and Function Primitives</title>
      <dc:creator>Brandon Satrom</dc:creator>
      <pubDate>Thu, 16 May 2019 19:29:19 +0000</pubDate>
      <link>https://forem.com/particle/get-up-to-speed-with-particle-variable-and-function-primitives-18</link>
      <guid>https://forem.com/particle/get-up-to-speed-with-particle-variable-and-function-primitives-18</guid>
      <description>&lt;p&gt;IoT Projects often need to share the data they collect, or enable external systems to trigger actions. That’s the “I” in IoT, after all. To make connectivity easier, Particle provides a number of “primitives” in the built-in Device OS, including variables, functions and messaging with Particle &lt;a href="https://docs.particle.io/reference/device-os/firmware/photon/#particle-publish-"&gt;publish and subscribe&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/POHyi5xV8Mc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this &lt;a href="https://www.youtube.com/watch?v=POHyi5xV8Mc"&gt;video&lt;/a&gt;, I walk through a simple project that shows you how to use the Particle Variable and Function primitives with a &lt;a href="https://store.particle.io/products/argon-kit"&gt;Particle Argon&lt;/a&gt;, and two Grove sensors from the &lt;a href="https://store.particle.io/products/grove-starter-kit"&gt;Grove Starter Kit for Particle Mesh&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With the variable and function primitives, developers can access local device state, for instance, to retrieve the latest reading from a connected sensor, or call firmware functions to take action on the device, for instance, to turn on a light or move a servo. Because these primitives are mediated securely through the Particle Device Cloud, they can be accessed from other devices, the Particle console, or even in web and mobile applications.&lt;/p&gt;

&lt;p&gt;For other videos covering the basics of working with Particle devices, check out our &lt;a href="https://www.youtube.com/watch?v=0T5rFu-9JAI&amp;amp;list=PLIeLC6NIW2tKvC5W007j_PU-dxONK_ZXR"&gt;Particle 101 series on YouTube&lt;/a&gt;. If you have questions about using Particle variables, functions, or anything else in the Particle platform, &lt;a href="https://community.particle.io"&gt;visit us in the Particle Community&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://blog.particle.io/2019/05/16/get-up-to-speed-with-particle-variable-and-function-primitives/"&gt;Get up to speed with Particle Variable and Function Primitives&lt;/a&gt; appeared first on &lt;a href="https://blog.particle.io"&gt;Particle Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>iot</category>
      <category>cpp</category>
      <category>embedded</category>
    </item>
    <item>
      <title>Three things I learned about Microsoft's IoT vision at Build</title>
      <dc:creator>Brandon Satrom</dc:creator>
      <pubDate>Fri, 10 May 2019 19:08:54 +0000</pubDate>
      <link>https://forem.com/bsatrom/three-things-i-learned-about-microsoft-s-iot-vision-at-build-e5h</link>
      <guid>https://forem.com/bsatrom/three-things-i-learned-about-microsoft-s-iot-vision-at-build-e5h</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Frgspek9xybmg1rr0uxfy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Frgspek9xybmg1rr0uxfy.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Photo by &lt;a href="https://unsplash.com/@leio?utm_medium=referral&amp;amp;utm_campaign=photographer-credit&amp;amp;utm_content=creditBadge" rel="noopener noreferrer"&gt;Leio McLaren (@leiomclaren) on Unsplash&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This week, I attended Microsoft's annual Build conference. It was my first trip back to build since the very first iteration many years ago—when I was a Microsoft employee and the star of the show was Windows 8!—and I was excited to see Microsoft's vision for developers, up close. &lt;/p&gt;

&lt;p&gt;There were a whirlwind of announcements across the three days in all areas of Microsoft's business, but as a maker and embedded developer, my primary interest was in the company's ever-increasing attention on the IoT. Here are three major things I learned about Microsoft's vision for the IoT from my time at Build.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The views and opinions expressed here are mine, and do not represent those of my employer, &lt;a href="https://particle.io" rel="noopener noreferrer"&gt;Particle&lt;/a&gt;. Nor are they meant to indicate any public statement about Particle product features, integrations, roadmap changes or shifts in strategy. This post is merely one developer's opinion and should be treated as such.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  "The Intelligent Edge" is an extension of Microsoft's long commitment to a hybrid cloud computing model
&lt;/h2&gt;

&lt;p&gt;Satya Nadella's keynote on day one of Build was a tight, two-hour whirlwind that touched on almost every area of Microsoft's business. Nadella framed his remarks around what he referred to as "four distinct platform opportunities" for Microsoft, each of which drove a section of the keynote. They were:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Intelligent Cloud &amp;amp; Edge&lt;/li&gt;
&lt;li&gt;Business Process Automation&lt;/li&gt;
&lt;li&gt;Office 365&lt;/li&gt;
&lt;li&gt;Gaming &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Microsoft CEO made only passing mention of "the IoT" in name during his keynote. Instead, he spent the first segment talking about edge computing, and the role he sees Azure playing in "extending the cloud to the edge." He invoked the term "hybrid cloud" more than a few times, and emphasized that a successful hybrid cloud environment requires "consistency between the cloud and the edge."&lt;/p&gt;

&lt;h3&gt;
  
  
  ABInBev and Srarbucks
&lt;/h3&gt;

&lt;p&gt;With those remarks as the frame, Nadella went on to share customers already using Azure to enable this form of edge-to-cloud hybrid computing, including ABInBev and Starbucks. Starbucks had an extensive expo hall demo of their Azure-powered products, including an Azure Machine Learning-powered customized ordering engine (Deep Brew) and an Azure IoT Central And Azure Sphere-powered system for monitoring and management of Starbuck's Mastrena II espresso machines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ftvt5u0nb8jslqnruvtex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ftvt5u0nb8jslqnruvtex.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Starbucks' AzureML powered DeepBrew recommendation system&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ft28eyq1xjr9tmv5zczdd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ft28eyq1xjr9tmv5zczdd.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Starbucks' white-labeled Azure IoT Central dashboard for espresso machine monitoring&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you've been a Microsoft-watcher for the last decade, the term "hybrid cloud" will sound familiar. It's one that Microsoft has been using since the very early days of Azure, when Ballmer's vision for hybrid was a mix of public cloud and private cloud compute resources that were seamlessly connected. The idea then was to ease the transition of wary enterprise customers into cloud computing, while enabling those same customers to explore the benefits of elastic compute resources without pivoting solely to the cloud. Whereas Amazon's AWS grew in its early days on the compute needs of startups averse to "owning iron," Microsoft's bread-and-butter was EA-signing enterprises who already had plenty of iron.&lt;/p&gt;

&lt;p&gt;Given that history—and as far as I'm aware Microsoft never really pivoted away from this narrative even as Azure has evolved in the last decade—it should come as no surprise that Microsoft sees the "IoT edge" as just another spoke in the hybrid cloud. In this world, your factory, farm, retail store, or truck is its own computing environment, and should sense, actuate and compute seamlessly with the rest of your business.&lt;/p&gt;

&lt;p&gt;The "hybrid cloud" is a powerful narrative that I'm sure has served the company well with traditional businesses in the last decade. After Build, I can see how it would be compelling to those same businesses as they pursue somewhat unfamiliar connectivity (read IoT) solutions.&lt;/p&gt;
&lt;h2&gt;
  
  
  Scott Guthrie shared the MSFT vision of ML on the edge with options
&lt;/h2&gt;

&lt;p&gt;After Nadella's keynote, the Build audience was invited to choose between two deep dive technical keynotes: one focused on Azure, and another the Office 365 and Dynamics platform. I opted for the Scott Guthrie-helmed Azure keynote, hoping for a bit more depth around the Intelligent Edge and IoT narratives from the keynote.&lt;/p&gt;

&lt;p&gt;As with the keynote, Guthrie's session covered a lot of ground, with product announcements and demos across all of the Azure stack and its associated developer tools. In the IoT realm, the conversation was again focused on hybrid cloud computing and their customers increased attention to building solutions that offload processing and decision-making "to the edge." This was especially apparent in amount of attention paid to the demos and solutions that featured an edge Machine Learning (ML) component. It was in that discussion that I learned something interesting about Microsoft's perspective on the edge and IoT.&lt;/p&gt;

&lt;p&gt;In the IoT universe of 2019, much of the focus on edge computing—especially as it relates to ML—is how to do ML on the edge using Single Board Computers and Microcontrollers. As SBCs and MCUs get beefier, it's becoming possible to perform ML inference—that is, performing a prediction against a pre-trained model; model training is still in the domain of more powerful computers—on constrained devices. &lt;/p&gt;

&lt;p&gt;In the world of Edge ML products, SBCs and MCUs have dominated. Google's TPU-based &lt;a href="https://coral.withgoogle.com/" rel="noopener noreferrer"&gt;Coral DevBoard&lt;/a&gt; and the NVIDIA &lt;a href="https://developer.nvidia.com/embedded/buy/jetson-nano-devkit" rel="noopener noreferrer"&gt;Jetson Nano&lt;/a&gt; are two examples of recently-released Pi-like SBCs with ML inference skills. SparkFun has released an &lt;a href="https://www.sparkfun.com/products/15170" rel="noopener noreferrer"&gt;Edge MCU&lt;/a&gt; that runs TensorFlow lite models, and the &lt;a href="https://os.mbed.com/blog/entry/uTensor-and-Tensor-Flow-Announcement/" rel="noopener noreferrer"&gt;announcement just this week&lt;/a&gt; at Google I/O of a unification between the &lt;a href="https://www.tensorflow.org/lite/" rel="noopener noreferrer"&gt;TensorFlow Lite&lt;/a&gt; and &lt;a href="https://github.com/utensor/" rel="noopener noreferrer"&gt;uTensor&lt;/a&gt; projects are strong signals that MCU-based inference is a reality.&lt;/p&gt;

&lt;p&gt;However, Microsoft seems to view edge ML a bit differently. The company didn't announce an ML-capable SBC or MCU at Build, nor did they disparage the existence of these products as frivolous. Instead, where much of the ML narrative of today seems to be heading toward a continuum of training in the cloud and inference on constrained devices, Microsoft painted a picture where a third computing option sits in the middle: one of edge servers and stacks that offload training from the cloud and inference from devices, while offering the same speed and security that makes edge ML so enticing in the first place. &lt;/p&gt;

&lt;p&gt;In floor demos and videos, they featured products like the Azure Stack, a rack of FPGA-powered cards for edge processing, the Azure DataBox for ingesting data by the terabyte into the cloud, and the &lt;a href="https://azure.github.io/Vision-AI-DevKit-Pages/#" rel="noopener noreferrer"&gt;Vision AI DevKit&lt;/a&gt;. The latter is probably the closest thing to an SBC-style ML device that Microsoft has, but even it was featured working in concert with other, higher-powered edge devices.&lt;/p&gt;

&lt;p&gt;The featured floor demo in this space was from Kroger, who is using the Vision AI DevKit, Azure Stack and DataBox Edge to perform out-of-stock detection on supermarket shelves without needing to backhaul streaming video to the cloud for ML processing and inference.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Feag3m1il5ipj8axozwx2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Feag3m1il5ipj8axozwx2.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A mockup booth of the Kroger stock detection system.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Microsoft didn't explicitly paint this story as an either-or between ML-capable SBCs or MCUs and their products, and they may very well have a product or two in the works as we speak. But one thing that was apparent to me is that when Microsoft thinks about the edge and the hybrid cloud, they think their customers need a variety of options to choose from when building IoT solutions, not just ML-capable SBCs/MCUs.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Microsoft's vision of the IoT is plug-and-play
&lt;/h2&gt;

&lt;p&gt;Perhaps you noticed that Microsoft made a few product announcements in the days and weeks leading up to Build this year. There's one &lt;a href="https://azure.microsoft.com/en-us/blog/intelligent-edge-innovation-across-data-iot-and-mixed-reality/" rel="noopener noreferrer"&gt;you might have missed&lt;/a&gt; as it was buried under a few others: IoT Plug and Play.&lt;/p&gt;

&lt;p&gt;I saw the [announcement when it dropped the Thursday before Build&lt;a href="https://azure.microsoft.com/en-us/blog/intelligent-edge-innovation-across-data-iot-and-mixed-reality/" rel="noopener noreferrer"&gt;&lt;/a&gt;, but I'll admit that I was skeptical. I read the announcement, and took a quick scan around the Azure IoT Device Catalog, but the entire thing felt like a marketing ploy to me: clever naming, but little news of value for the IoT developer.&lt;/p&gt;

&lt;p&gt;Turns out, I was wrong. In a few sessions from Sam George, Peter Provost and Briton Zurcher on Monday and Tuesday, I realized that the Plug and Play naming was more than branding. As it turns out, a plug and play model might just be exactly what the IoT needs to make solution development easier.&lt;/p&gt;

&lt;p&gt;Think about a typical IoT solution of today. You select an MCU or SBC to be the brains of the project, then populate it with sensors and actuators to do something. In some cases, you might even buy a self-contained product like a dashcam or streaming video camera and connect it directly to Wi-Fi. You write firmware to interface with devices, and then you connect the product and its various sensors and actuators to the cloud.&lt;/p&gt;

&lt;p&gt;Often, this step of wiring a physical product up to a cloud solution is the challenging part. Connectivity, security and messaging (MQTT, TCP, AMQP, etc.) aside, even the act of defining the telemetry data that your solution will capture and send, or the cloud to device commands it responds to requires manual work in firmware and in cloud solutions like Azure IoT Central.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://azure.microsoft.com/en-us/blog/build-with-azure-iot-central-and-iot-plug-and-play/" rel="noopener noreferrer"&gt;IoT Plug and Play&lt;/a&gt; is Microsoft's open source, standards-based answer to this problem. The secret sauce here is a JSON-LD schema called a Device Capability Model, which can be used to define device metadata like who makes it, what firmware version it's running, what telemetry it sends and collects, and what cloud-side commands it responds to. Here's an example of a capability model from the &lt;a href="https://github.com/Azure/IoTPlugandPlay/tree/master/DTDL" rel="noopener noreferrer"&gt;capability model spec&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://example.com/thermostatDevice/1.0.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CapabilityModel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;displayName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thermostat T-1000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;implements&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://example.com/thermostat/1.0.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Interface&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;displayName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thermostat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contents&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Telemetry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;temp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;schema&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;double&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Property&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;setPointTemp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;writable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;schema&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;double&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://azureiot.com/v0/contexts/Interface.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://azureiot.com/interfaces/deviceInformation/1.1.3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://azureiot.com/v0/contexts/CapabilityModel.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://azureiot.com/v0/contexts/Interface.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The advantage of a capability model like this is that it creates a contract between the disparate systems in an IoT solution. It can be plugged into a SaaS product like Azure IoT Central and recognize telemetry and commands automatically. It can be used to generate C/C++ code to collect telemetry or respond to commands. It can even be used by developer tools and IDEs (like VS Code) to auto-generate capability models based on implementation-specific firmware.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fryitk3hqpm3diwppo44b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fryitk3hqpm3diwppo44b.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An overview of how IoT Plug and Play enables various aspects of the solution development process.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And much as Plug and Play of 90s-era Microsoft Windows enabled consumers to buy third-party peripherals and trust that they would "just work," IoT Plug and Play seeks to enable the same experiences for IoT solution builders and device manufacturers alike. And because the &lt;a href="https://github.com/Azure/IoTPlugandPlay" rel="noopener noreferrer"&gt;underlying definition language is open source&lt;/a&gt;, I'm quite hopeful that this will be picked up and leveraged well-beyond the Microsoft ecosystem.&lt;/p&gt;

&lt;p&gt;I meet a lot of makers, embedded and hardware engineers in my work for Particle. One of the things we often find ourselves saying to each other is that there's never been a better time to do what we do. Dev kits are cheaper than ever; resources abound on places like &lt;a href="https://www.youtube.com/channel/UCpYjkSkGOXAMXeZjZkbb-PQ" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;, &lt;a href="https://twitch.tv/brandonsatrom" rel="noopener noreferrer"&gt;Twitch&lt;/a&gt;, &lt;a href="https://hackster.io" rel="noopener noreferrer"&gt;Hackster&lt;/a&gt;, and &lt;a href="https://hackaday.io" rel="noopener noreferrer"&gt;Hackaday&lt;/a&gt;; IoT vendors like &lt;a href="https://particle.io" rel="noopener noreferrer"&gt;Particle&lt;/a&gt; continue to build simple, secure and scale-ready platforms; and &lt;a href="https://adafruit.com" rel="noopener noreferrer"&gt;Adafruit&lt;/a&gt; is there to make sure we never stop having fun while building things.&lt;/p&gt;

&lt;p&gt;If you're looking to solve a real-world problem in the IoT space, there's never been a better time to dig in. Microsoft seems to agree, and after what I've seen this week, I think all of us working in this space stand to benefit, now and in the future.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>microsoft</category>
      <category>iot</category>
      <category>news</category>
    </item>
    <item>
      <title>Professional debugging for IoT with VS Code &amp; Particle Workbench: going beyond Serial.print()</title>
      <dc:creator>Brandon Satrom</dc:creator>
      <pubDate>Fri, 03 May 2019 18:45:31 +0000</pubDate>
      <link>https://forem.com/particle/professional-debugging-for-iot-with-vs-code-particle-workbench-going-beyond-serial-print-3hc6</link>
      <guid>https://forem.com/particle/professional-debugging-for-iot-with-vs-code-particle-workbench-going-beyond-serial-print-3hc6</guid>
      <description>&lt;p&gt;I started my career in technology as a web developer back in 1999. Those halcyon days of the early web were much different than today, with no browser dev tools, not a sniff of HTML5, and JavaScript was still in its pre-AJAX infancy. But I pinned for a world where on-device debugging would be as easy as my browser dev tools.&lt;/p&gt;

&lt;p&gt;Today I pine no more, and with the recent launch of &lt;a href="https://www.particle.io/workbench/"&gt;Particle Workbench&lt;/a&gt;, I’ve finally found a tool that makes hardware device debugging as easy to use as the browser dev tools. In this post, I’ll walk through how you can do the same with your Particle devices today!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: this post covers the basics of debugging with 3rd Generation particle devices, like the Argon, Boron, and Xenon. The Particle docs have an &lt;a href="https://docs.particle.io/tutorials/developer-tools/workbench/#debugging-3rd-generation-"&gt;excellent, comprehensive guide for 3rd generation debugging&lt;/a&gt;, as well as a &lt;a href="https://docs.particle.io/tutorials/developer-tools/workbench/#debugging-2nd-generation-with-particle-debugger-"&gt;guide for debugging 2nd Generation devices (Photon, Electron)&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Brief history of my debugging experience: it’s an art
&lt;/h2&gt;

&lt;p&gt;In my early development days, the state of the art in JavaScript debugging was the &lt;code&gt;alert&lt;/code&gt; command, which would pop a UI box on ones screen with whatever value you wanted it to. Need to know the current state of a loop counter variable? &lt;code&gt;alert(i);&lt;/code&gt; Wondering what the &lt;code&gt;ADDRESS_ONE&lt;/code&gt; column looks like when retrieved from your SQL Server database? &lt;code&gt;alert(address_one)&lt;/code&gt;.&lt;/p&gt;


&lt;center&gt;&lt;p id="attachment_5178"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UCGCkpYn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/0291g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UCGCkpYn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/0291g.png" alt="Image of a browser alert box from IE 6" width="493" height="203"&gt;&lt;/a&gt;The state of the art in debugging, circa 1999.&lt;/p&gt;&lt;/center&gt;

&lt;p&gt;Desperately trying to figure out where that heisenbug is in your new user auth flow that you swore to your boss up and down you tested thoroughly before deploying on a Friday at 4pm?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alert(“HERE”); 

alert(“HERE 2”);

alert(“WHAT ARE WEEKENDS ANYWAY? I LIVE IN THIS CUBICLE NOW.”);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the years since, the state of debugging in the web has come a long way. With the advent of &lt;code&gt;console.log()&lt;/code&gt;, we got the unobtrusive replacement for the alertbox. It was a move in the right direction, but still a Crocodile Dundee-sized knife when one needed a scalpel.&lt;/p&gt;

&lt;p&gt;Then came browser developer tools, first in Firefox via Firebug, then built-in in Chrome, Firefox, IE, and Opera. Finally, web developers everywhere could set breakpoints, watches, and inspect running client-side applications like our server-focused colleagues had been doing for years.&lt;/p&gt;

&lt;h3&gt;
  
  
  Serial.print(), the alert() of embedded development
&lt;/h3&gt;

&lt;p&gt;Many years later, I got into hardware and embedded development, and I discovered that a similar trial and error debugging process dominated the field in a way not unlike the early web. There, instead of &lt;code&gt;alert()&lt;/code&gt; and &lt;code&gt;console.log()&lt;/code&gt;, the tendency was to litter ones firmware with &lt;code&gt;Serial.print()&lt;/code&gt; and &lt;code&gt;Serial.println()&lt;/code&gt; commands as a way of logging the progress and state of an embedded application.&lt;/p&gt;

&lt;p&gt;And much like my early use of &lt;code&gt;alert()&lt;/code&gt;, I found myself using &lt;code&gt;Serial.print()&lt;/code&gt; as a blunt instrument when things went awry and I had no idea where the self-induced error was to be found. Sure, professional, on-device debugging tools were available, but as a newbie in this intimidating world of hardware, I, like many others, reached for the solution that felt comfortable and familiar.&lt;/p&gt;

&lt;p&gt;With the launch of Particle Workbench, I’m happy to report that the built-in debugging capabilities are just what we firmware developers need to go beyond &lt;code&gt;Serial.print()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging with Particle Workbench: Easy like the browser dev tools
&lt;/h2&gt;

&lt;p&gt;Before getting started, you’ll need to gather a few materials, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.particle.io/workbench/"&gt;Particle Workbench&lt;/a&gt;, a new VS Code-based IDE optimized for IoT;&lt;/li&gt;
&lt;li&gt;One 3rd Generation Particle device. I use the &lt;a href="https://store.particle.io/products/argon-kit"&gt;Argon Kit&lt;/a&gt; for this post;&lt;/li&gt;
&lt;li&gt;One &lt;a href="https://store.particle.io/products/particle-debugger"&gt;Particle Debugger&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;One USB Micro cable (included in the Argon Kit I used).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both the Debugger and the Particle device must be connected to the same computer via USB, so make sure you have enough ports available. Connect the debugger to the debug port on your Particle device using the provided ribbon cable, and plug both into your computer. The debug port consists of ten exposed pins protected by some plastic, and you can find it next to the LiPo battery port near the top of the device.&lt;/p&gt;


&lt;center&gt;&lt;p id="attachment_5182"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aIKamUYA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/DebuggerCable.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aIKamUYA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/DebuggerCable.png" alt="" width="600" height="600"&gt;&lt;/a&gt;The debugger cable plugs into the 10-pin JTAG port on the top left of the device.&lt;/p&gt;&lt;/center&gt;

&lt;p&gt;Once everything is connected and powered on, you’ll need to put your Particle device into Device Firmware Update (DFU) mode. In order for Workbench to facilitate on-device debugging, it needs to compile and flash a debug build of your application and the Particle Device OS firmware in a single binary. You’ll sometimes see this referred to as a “monolithic” build because this differs from the normal build process, where Device OS and your application firmware can be updated independent of one another.&lt;/p&gt;

&lt;p&gt;To put your device in DFU mode, press and hold the MODE and RESET buttons on the device. Then, release the RESET button, while continuing to hold the MODE button until the RGB LED on the device starts blinking yellow.&lt;/p&gt;


&lt;center&gt;&lt;p id="attachment_5183"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3bg1VcLp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/DFU.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3bg1VcLp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/DFU.gif" alt="Gif of a Particle Argon being put into DFU mode" width="320" height="259"&gt;&lt;/a&gt;Put your device into DFU mode before starting the debug process.&lt;/p&gt;&lt;/center&gt;

&lt;p&gt;&lt;em&gt;Note: Step debugging 3rd generation devices with Mesh features enabled is currently unsupported due to requirements of the Nordic SoftDevice in the nrf52840. Devices in standalone mode, which is configurable during mobile setup, can be debugged with no issues.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Workbench Debugging Basics
&lt;/h3&gt;

&lt;p&gt;Now that you’re setup on the hardware side, let’s start a debugging session and cover some Workbench basics. First, you’ll need to open a firmware project with Particle Workbench. I won’t cover the specifics of creating or importing projects in Workbench, so be sure to consult the &lt;a href="https://docs.particle.io/workbench/"&gt;docs&lt;/a&gt; if you need more info.&lt;/p&gt;
&lt;h4&gt;
  
  
  Starting a Debug Session
&lt;/h4&gt;

&lt;p&gt;To start a debug session, click on the Debug icon to open the debug sidebar. Then click the debug dropdown and select the “Particle Debugger (argon, boron, xenon)” option.&lt;/p&gt;


&lt;center&gt;&lt;p id="attachment_5184"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7NQ1sLqT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/DebugMenu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7NQ1sLqT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/DebugMenu.png" alt="Image of selecting the Particle Debugger from the VS Code debug meny" width="450" height="482"&gt;&lt;/a&gt;The debug sidebar icon is… a bug. Pretty easy to spot, which is more than I can say for the bugs I tend to create in my code.&lt;/p&gt;&lt;/center&gt;

&lt;p&gt;Now, get ready to wait a bit as Workbench creates a debug binary for your project. This will go much faster on repeat runs, but the first run is a good time to grab a cup of coffee, take a stretch break, or practice your &lt;a href="https://xkcd.com/303/"&gt;sword-fighting in the hallway&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once the debug binary is built and flashed to your device, Workbench will halt and your device will power down, which you’ll see once the onboard RGB LED turns off. You’ll also see the following message in the Debug Console, which is expected.&lt;/p&gt;


&lt;center&gt;&lt;p id="attachment_5185"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4YdV7Z7P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/DebugConsole.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4YdV7Z7P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/DebugConsole.png" alt="An Image of the debug Console in Particle Workbench" width="500" height="212"&gt;&lt;/a&gt;The message here is normal when starting a debug session&lt;/p&gt;&lt;/center&gt;

&lt;p&gt;Click the continue button to power your device back up. Once you’re breathing cyan again, you’re ready to debug!&lt;/p&gt;


&lt;center&gt;&lt;p id="attachment_5186"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VAqvIbDE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/ContinueButton.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VAqvIbDE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/ContinueButton.png" alt="Image of the debug menu with the continue button called out in a red rectangle" width="500" height="281"&gt;&lt;/a&gt;The continue button is the play button at the left of the step debugging box.&lt;/p&gt;&lt;/center&gt;
&lt;h4&gt;
  
  
  Setting Breakpoints
&lt;/h4&gt;

&lt;p&gt;The first thing you’ll likely want to do is set some breakpoints so you can pause and inspect running code. You can set breakpoints by clicking in the gutter next to an individual line, or from the “Breakpoints” section of the debug sidebar. When a breakpoint is set, a red circle will appear next to the line on which to break.&lt;/p&gt;


&lt;center&gt;&lt;p id="attachment_5188"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--llZ2msyG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/DebugSidebar.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--llZ2msyG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/DebugSidebar.png" alt="Image of a code snippet with a single line set as a breakpoint" width="600" height="357"&gt;&lt;/a&gt;Click on the gutter next to any line to set a breakpoint&lt;/p&gt;&lt;/center&gt;


&lt;center&gt;&lt;p id="attachment_5187"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c_dtNKZa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/DebugSide.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c_dtNKZa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/DebugSide.png" alt="Image of setting a breakpoint using the sidebar" width="450" height="125"&gt;&lt;/a&gt;You can also add breakpoints in the sidebar by referencing a function by name&lt;/p&gt;&lt;/center&gt;

&lt;p&gt;It’s also possible to set breakpoints that only break code when a condition you define is met. You can set conditional breakpoints that pause execution when a condition is true, or when a hit counter is passed. In the screenshot below, I’ve set a breakpoint to pause when an Ultrasonic distance sensor reads a value less than 100 cm.&lt;/p&gt;


&lt;center&gt;&lt;p id="attachment_5190"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6cBlP6X6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/ConditionalBreakpoint.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6cBlP6X6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/ConditionalBreakpoint.png" alt="Image of a conditional breakpoint" width="600" height="166"&gt;&lt;/a&gt;Use conditional breakpoints when you want to fine-tune how and when to break on a line of code.&lt;/p&gt;&lt;/center&gt;
&lt;h4&gt;
  
  
  Stepping through code
&lt;/h4&gt;

&lt;p&gt;Once a breakpoint is hit, the line in question will be highlighted in yellow. From here, you can use the Debug menu at the top of the screen to step through your code. From left to right in the image below, those buttons allow you to continue, step over the current line, step into the current line, step out of the current scope, restart the debug session (you’ll need to put the device back in DFU mode for this to work) and finally, to disconnect the session.&lt;/p&gt;


&lt;center&gt;&lt;p id="attachment_5191"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZpyZIIMT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/DebugMenuTop.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZpyZIIMT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/DebugMenuTop.png" alt="Image of the debug menu in Particle Workbench" width="339" height="69"&gt;&lt;/a&gt;During debugging, this handy menu will appear at the top of your Workbench screen.&lt;/p&gt;&lt;/center&gt;

&lt;p&gt;Hitting continue resumes execution until the next breakpoint is hit. Most of the time, you’ll end up using the step into, over and out buttons to explore your code.&lt;/p&gt;


&lt;center&gt;&lt;p id="attachment_5192"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--El9_1m6L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/HighlightBreak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--El9_1m6L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/HighlightBreak.png" alt="image of code with the debugger paused on a breakpoint" width="600" height="223"&gt;&lt;/a&gt;When paused on a breakpoint, the current line will be highlighted in yellow.&lt;/p&gt;&lt;/center&gt;

&lt;p&gt;Let’s consider the difference between stepping over and into the following line of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;range = ultrasonic.MeasureInCentimeters();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Clicking step over will move execution to the next line, &lt;code&gt;Serial.print()&lt;/code&gt; and pause again. From here, you can inspect variables, the call stack, and more. If the line in question is a function, you can also step into the source of that function. This is really handy when debugging in firmware libraries, like in the case of the &lt;code&gt;MeasureInCentimeters&lt;/code&gt; function, which is part of the &lt;a href="https://build.particle.io/libs/Grove-Ultrasonic-Ranger/1.0.1/tab/Ultrasonic.cpp"&gt;Grove-Ultrasonic-Ranger&lt;/a&gt; library!&lt;/p&gt;


&lt;center&gt;&lt;p id="attachment_5194"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D2-IQvPm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/StepInto.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D2-IQvPm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/StepInto.gif" alt="Gif of step debugging into a library function" width="480" height="372"&gt;&lt;/a&gt;The debugger can step into locally-installed firmware libraries&lt;/p&gt;&lt;/center&gt;

&lt;p&gt;Once inside a function, you can use the “Step Out” option to continue execution through the rest of the current function and break again on the next line after that function returns.&lt;/p&gt;

&lt;p&gt;Step debugging allows you to inspect your code, code in firmware libraries, and even sources in the Device OS firmware! Ever wanted to explore the internals of how Particle’s brilliant firmware team implemented &lt;code&gt;Particle.publish()&lt;/code&gt;? With Workbench debugging, you can!&lt;/p&gt;


&lt;center&gt;&lt;p id="attachment_5242"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0xiH_6h6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/PublishStepIntoOpt.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0xiH_6h6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/PublishStepIntoOpt.gif" alt="Gif of stepping into a Particle.publish function call" width="640" height="424"&gt;&lt;/a&gt;You can also step-debug into Device OS internals!&lt;/p&gt;&lt;/center&gt;
&lt;h4&gt;
  
  
  Inspecting variables
&lt;/h4&gt;

&lt;p&gt;Step debugging is magical in itself, I know. Often, however, the reason we need to debug in the first place is to check the state of our application when it reaches a breakpoint. Workbench provides a number of ways for you to do this. To begin with, when paused on a breakpoint, you can hover over a variable or object and a tooltip will appear with information about its state. You can also inspect the values of local and global variables using the Variables panel.&lt;/p&gt;


&lt;center&gt;&lt;p id="attachment_5198"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Se8cKmqy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/VariablesPanel.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Se8cKmqy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/VariablesPanel.png" alt="image of the variables panel with local and global variables" width="450" height="606"&gt;&lt;/a&gt;The variables panel contains information about local, global and static state&lt;/p&gt;&lt;/center&gt;
&lt;h4&gt;
  
  
  Watching values
&lt;/h4&gt;

&lt;p&gt;Beyond inspecting local and global variables, you can use the watch panel to tell the debugger to keep track of the state of a given variable or object. This can be quite useful if you want to see how a portion of your application mutates or is affected by another variable, or if you want to take a closer look at when a given variable or object comes into or goes out of scope as your app is running.&lt;/p&gt;


&lt;center&gt;&lt;p id="attachment_5196"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p_X4LxY3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/Watch.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p_X4LxY3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/Watch.gif" alt="Gif of the watch panel with a value changing" width="640" height="274"&gt;&lt;/a&gt;The watch panel is useful for keeping track of state while you debug&lt;/p&gt;&lt;/center&gt;
&lt;h4&gt;
  
  
  Navigating the call stack
&lt;/h4&gt;

&lt;p&gt;One of my favorite debugging features is the Call Stack navigator, which can come in quite handy when you’re spelunking the internals of a library or the Device OS firmware. The pane keeps running track of the stack from your current position up, and you can click on any entry in the stack to quickly navigate to that position.&lt;/p&gt;


&lt;center&gt;&lt;p id="attachment_5243"&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NvBTKQTP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/CallStackBigOpt.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NvBTKQTP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/05/CallStackBigOpt.gif" alt="" width="640" height="388"&gt;&lt;/a&gt;With the Call Stack panel, you can move around anywhere in the stack of the current breakpoint&lt;/p&gt;&lt;/center&gt;
&lt;h4&gt;
  
  
  Advanced Debugging Features
&lt;/h4&gt;

&lt;p&gt;In addition to the features covered in this post, the Workbench debugger provides access to several debug features built-in to VS Code and leveraged by the cortex-debug extension, including the ability to inspect and edit hardware registers, peripherals, and even direct memory locations. All of these are outside of the scope of this post, so check out the &lt;a href="https://code.visualstudio.com/docs/editor/debugging"&gt;docs for these tools&lt;/a&gt; to learn more about how to use them.&lt;/p&gt;

&lt;h4&gt;
  
  
  Additional Tips and Tricks
&lt;/h4&gt;

&lt;p&gt;Once you’re done debugging and ready to resume normal coding and flashing, you’ll need to get your device out of its debug state, meaning that you want to replace the “monolithic” debug build with the hybrid application and device OS firmware. To do this, put the device back into DFU mode and run the “&lt;code&gt;Particle: Flash application &amp;amp; Device OS (local)&lt;/code&gt;” command in the Workbench command palette.&lt;/p&gt;

&lt;p&gt;And if you ever run into weird errors while debugging or flashing, the Workbench clean commands are your friends! In my experience, when these things pop up, running “&lt;code&gt;Particle: Clean application &amp;amp; Device OS (local)&lt;/code&gt;” and “&lt;code&gt;Particle: Clean application for debug (local)&lt;/code&gt;” are usually enough to set things right again.&lt;/p&gt;

&lt;p&gt;Much as the web has come a long way since the early days of &lt;code&gt;alert()&lt;/code&gt;-based debugging, the built-in debugging capabilities of Particle Workbench will enable Particle developers everywhere to peer under the covers of their embedded applications with ease and confidence. Debugging with Particle Workbench is already a game-changer for me, and I bet it will be for you too.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://blog.particle.io/2019/05/03/professional-debugging-for-iot-with-particle-workbench-going-beyond-serial-print/"&gt;Professional debugging for IoT with Particle Workbench: going beyond Serial.print()&lt;/a&gt; appeared first on &lt;a href="https://blog.particle.io"&gt;Particle Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>cpp</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to build a control panel for your Particle-powered brewing projects</title>
      <dc:creator>Brandon Satrom</dc:creator>
      <pubDate>Wed, 27 Mar 2019 21:13:02 +0000</pubDate>
      <link>https://forem.com/particle/how-to-build-a-control-panel-for-your-particle-powered-brewing-projects-28m5</link>
      <guid>https://forem.com/particle/how-to-build-a-control-panel-for-your-particle-powered-brewing-projects-28m5</guid>
      <description>&lt;p&gt;A few weeks ago, I &lt;a href="https://dev.to/particle/upcycling-an-old-homebrewing-project-with-a-particle-argon-587k"&gt;detailed my process&lt;/a&gt; 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.&lt;/p&gt;

&lt;p&gt;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 &lt;a href="http://(https://twitch.tv/brandonsatrom)" rel="noopener noreferrer"&gt;live-streaming all my work on this project over on Twitch&lt;/a&gt;, 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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Designing a new PCB with Eagle and OSH park
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FBoardIterations.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FBoardIterations.png" alt="Various iterations of the Brew Buddy board"&gt;&lt;/a&gt;Various iterations of the Brew Buddy custom PCB that I’ve used over the years.&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating PCBs in Autodesk Eagle
&lt;/h4&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Replace the Photon with the Argon&lt;/li&gt;
&lt;li&gt;Re-route the pins to the proper places on the Argon&lt;/li&gt;
&lt;li&gt;Add an additional pin for the SD card chip-select on the Adafruit TFT breakout&lt;/li&gt;
&lt;li&gt;Add the Piezo disc (and resistor)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FBBSchematic-1024x423-test-1024x423.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FBBSchematic-1024x423-test-1024x423.png"&gt;&lt;/a&gt;A side-by-side comparison of the Brew Buddy schematic.&lt;/p&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FBBLayout-1024x703.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FBBLayout-1024x703.png"&gt;&lt;/a&gt;A side-by-side comparison of the Brew Buddy layout&lt;/p&gt;

&lt;p&gt;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?&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/AQd3qdI9BUE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  Ordering PCBs from OSH Park
&lt;/h4&gt;

&lt;p&gt;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 &lt;a href="https://oshpark.com/" rel="noopener noreferrer"&gt;OSH Park&lt;/a&gt;. They are inexpensive, quick, and if you like the color purple, you’ll love their PCBs.&lt;/p&gt;

&lt;p&gt;Ordering PCBs from OSH Park is simple. All you need to do is drag the Eagle &lt;code&gt;.brd&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;OSH park also allows you to make your PCBs publicly available for others to consume and even order. &lt;a href="https://oshpark.com/shared_projects/PQWUFWaS" rel="noopener noreferrer"&gt;Here’s mine&lt;/a&gt; for the Brew Buddy if you’d like to take a look for yourself.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/33dgf-r6pe4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Building a web-based control panel with Azure IoT and electric io
&lt;/h3&gt;

&lt;p&gt;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 &lt;a href="https://github.com/noopkat/electric-io" rel="noopener noreferrer"&gt;electric io&lt;/a&gt;, I was able to do just that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FScreenshot-2019-03-27-08.40.58-1024x689.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FScreenshot-2019-03-27-08.40.58-1024x689.png"&gt;&lt;/a&gt;My electric io dashboard for Brew Buddy&lt;/p&gt;

&lt;p&gt;The entire process consisted of the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wire my project up to Azure IoT Hub&lt;/li&gt;
&lt;li&gt;Configure electric io to display device data&lt;/li&gt;
&lt;li&gt;Add MQTT to my Firmware to receive cloud-to-device (C2D) messages from Azure&lt;/li&gt;
&lt;li&gt;Configure electric io to Send C2D Messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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 &lt;a href="https://blog.particle.io/2018/09/28/create-the-dashboard-of-your-dreams-with-particle-electric-io/" rel="noopener noreferrer"&gt;covered the second step in a recent blog post&lt;/a&gt;, 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.&lt;/p&gt;

&lt;h4&gt;
  
  
  Using MQTT to listen for Azure IoT Hub Messages
&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://docs.particle.io/tutorials/integrations/azure-iot-hub/" rel="noopener noreferrer"&gt;Particle Device Cloud to Azure IoT Hub integration&lt;/a&gt; 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;For Particle devices, there are two great MQTT libraries to choose from, &lt;a href="https://github.com/hirotakaster/MQTT" rel="noopener noreferrer"&gt;MQTT&lt;/a&gt; for basic support, and &lt;a href="https://github.com/hirotakaster/MQTT-TLS" rel="noopener noreferrer"&gt;MQTT-TLS&lt;/a&gt; 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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include “MQTT-TLS.h”
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &lt;code&gt;certs/h&lt;/code&gt; in my project, which I included right after the MQTT library include.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"certs/certs.h"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &lt;code&gt;{your hub name}&lt;/code&gt; string with the name of your own Azure IoT Hub, which you can find in the Azure Portal for your account.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;mqttCB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MQTT&lt;/span&gt; &lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{your hub name}.azure-devices.net"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8883&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mqttCB&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enableTls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;certificates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;certificates&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deviceID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"{your hub name}.azure-devices.net/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;deviceID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="s"&gt;"SharedAccessSignature {your SAS Token here}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the case of the Azure IoT Hub, the username you provide should be your hub endpoint—like &lt;code&gt;myhub.azure-devices.net—plus&lt;/code&gt; your Particle deviceID.&lt;/p&gt;

&lt;p&gt;For the password, &lt;a href="https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-security" rel="noopener noreferrer"&gt;Azure requires&lt;/a&gt; that you provide a SharedAccessSignature, or SAS Token. You can generate these for your own hubs with the Azure &lt;a href="https://github.com/Azure/azure-iot-sdk-csharp/blob/master/tools/DeviceExplorer" rel="noopener noreferrer"&gt;device explorer&lt;/a&gt;, the &lt;a href="https://docs.microsoft.com/en-us/cli/azure/ext/azure-cli-iot-ext/iot/hub?view=azure-cli-latest#ext-azure-cli-iot-ext-az-iot-hub-generate-sas-token" rel="noopener noreferrer"&gt;Azure CLI&lt;/a&gt; or the &lt;a href="https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.azure-iot-tools" rel="noopener noreferrer"&gt;Azure IoT Tools for VS Code&lt;/a&gt;, which is what I did. I was already in VSCode building my app with Particle Workbench, so it was easy!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FVSCode.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FVSCode.gif"&gt;&lt;/a&gt;The Azure IoT Hub VSCode extension in action&lt;/p&gt;

&lt;p&gt;The next step is to check the &lt;code&gt;isConnected&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;devices/{deviceID}/messages/devicebound/#&lt;/code&gt; topic filter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isConnected&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="n"&gt;Particle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mqtt/status"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"connected"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;msgSubResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"devices/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;deviceID&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; 
    &lt;span class="s"&gt;"/messages/devicebound/#"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MQTT&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;QOS0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;Particle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mqtt/message-sub-result"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msgSubResult&lt;/span&gt; 
    &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"subscribed to hub messages"&lt;/span&gt; 
    &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"subscription failed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Particle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mqtt/status"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"failed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &lt;code&gt;methodName&lt;/code&gt;, 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 &lt;code&gt;methodName&lt;/code&gt;. Thankfully, there’s a great &lt;a href="https://github.com/rickkas7/JsonParserGeneratorRK" rel="noopener noreferrer"&gt;JsonParserGenerator library&lt;/a&gt; for just this purpose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;mqttCB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;byte&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;pload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
  &lt;span class="n"&gt;memcpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
  &lt;span class="n"&gt;pload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

  &lt;span class="n"&gt;jsonParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
  &lt;span class="n"&gt;jsonParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;methodName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
      &lt;span class="n"&gt;jsonParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getReference&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"methodName"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;valueString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 

    &lt;span class="n"&gt;Particle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mqtt/message-method"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methodName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

    &lt;span class="n"&gt;setBrewMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;methodName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method takes the payload byte array, converts it to a character array, loads it into the &lt;code&gt;jsonParser&lt;/code&gt;, and extracts the &lt;code&gt;methodName&lt;/code&gt; from the payload before calling the &lt;code&gt;setBrewMode&lt;/code&gt; function, which [fires off a number of actions based on the mode string](http://(&lt;a href="https://github.com/bsatrom/brew-buddy/blob/master/brew-buddy-firmware/src/brew-buddy-firmware.ino#L365" rel="noopener noreferrer"&gt;https://github.com/bsatrom/brew-buddy/blob/master/brew-buddy-firmware/src/brew-buddy-firmware.ino#L365&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;With MQTT in place, I was able to turn my electric io dashboard into a control panel!&lt;/p&gt;

&lt;h4&gt;
  
  
  Sending Messages from Electric IO to a Particle-powered project
&lt;/h4&gt;

&lt;p&gt;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.”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FCreateButton.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FCreateButton.gif"&gt;&lt;/a&gt;Creating a new button card in electric io&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;{‘methodName’: ‘brew’}&lt;/code&gt; to tell my device to move into brewing mode.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FBrewMessage.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FBrewMessage.gif"&gt;&lt;/a&gt;Defining the button call type and payload&lt;/p&gt;

&lt;p&gt;After saving button settings, the card will change into just a title and button. To test, I can just click away!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FStartBrew.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FStartBrew.gif"&gt;&lt;/a&gt;Triggering a C2D Message with electric io&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FStartBrewDevice.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.particle.io%2Fwp-content%2Fuploads%2F2019%2F03%2FStartBrewDevice.gif"&gt;&lt;/a&gt;Brewing begins when the message is received!&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s next?
&lt;/h3&gt;

&lt;p&gt;As an &lt;a href="https://dev.to/bsatrom/building-iot-firmware-with-azure-pipelines-and-particle-2m30"&gt;endless tinkerer&lt;/a&gt;, 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.&lt;/p&gt;

&lt;p&gt;I suppose the next logical step is to brew some beer!&lt;/p&gt;

&lt;p&gt;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!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://youtu.be/33dgf-r6pe4" rel="noopener noreferrer"&gt;Part 5 – PCB Soldering and Assembly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/t-lQW4xnHA4" rel="noopener noreferrer"&gt;Part 6 – Implementing Sleep modes and fermentation support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/GVgVbZCyZ5w" rel="noopener noreferrer"&gt;Part 7 – Integrating Brew Buddy with Azure IoT Hub and electric io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/eJM_d4UVQ9Y" rel="noopener noreferrer"&gt;Part 8 – Adding MQTT Support to Brew Buddy firmware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/GJ9Qs-vwPyU" rel="noopener noreferrer"&gt;Part 9 – Adding MQTT Support (continued)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/ZMyPXpL0l44" rel="noopener noreferrer"&gt;Part 10 – Implementing C2D Message Support in electric io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/Iol2KemBENE" rel="noopener noreferrer"&gt;Part 11 – Implementing C2D Message Support in electric io (continued)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The post &lt;a href="https://blog.particle.io/2019/03/27/how-to-build-a-control-panel-for-your-particle-powered-brewing-projects/" rel="noopener noreferrer"&gt;How to build a control panel for your Particle-powered brewing projects&lt;/a&gt; appeared first on &lt;a href="https://blog.particle.io" rel="noopener noreferrer"&gt;Particle Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>programming</category>
      <category>web</category>
      <category>iot</category>
    </item>
    <item>
      <title>Building IoT Firmware with Azure Pipelines and Particle</title>
      <dc:creator>Brandon Satrom</dc:creator>
      <pubDate>Tue, 19 Mar 2019 16:11:29 +0000</pubDate>
      <link>https://forem.com/bsatrom/building-iot-firmware-with-azure-pipelines-and-particle-2m30</link>
      <guid>https://forem.com/bsatrom/building-iot-firmware-with-azure-pipelines-and-particle-2m30</guid>
      <description>&lt;p&gt;&lt;em&gt;TL;DR With Azure Pipelines and the Particle CLI, it's easy to create pipelines to automatically build IoT device firmware, release binaries, and even run automated tests!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ever have one of those hobby projects that keeps coming up again and again? You get inspired to start, frantically work on it for a while, then set it aside because life and work happen. &lt;/p&gt;

&lt;p&gt;Or maybe you get spooked by the thing and slowly (or quickly) back away?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9lspe03wxk12ash1hzlm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9lspe03wxk12ash1hzlm.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Why is the cat scared of the banana? Maybe he just went Keto.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I know that feeling of dread, especially when it comes to hobby projects. &lt;/p&gt;

&lt;p&gt;And yet, there are some that never truly go away. You ruminate on them. You tinker with them a little every once in a while. You keep adding features to your wishlist. The inspiration (or fear) never truly fades, and some part of you just knows that you'll finish that thing one day. &lt;/p&gt;

&lt;p&gt;One such project for me is the &lt;a href="https://github.com/bsatrom/brew-buddy" rel="noopener noreferrer"&gt;Brew Buddy&lt;/a&gt;. A &lt;a href="https://particle.io" rel="noopener noreferrer"&gt;Particle-powered&lt;/a&gt; homebrew monitoring rig that I started over three years ago. I started the project with the &lt;a href="https://docs.particle.io/photon/" rel="noopener noreferrer"&gt;Particle Photon&lt;/a&gt;, an &lt;a href="https://adafruit.com" rel="noopener noreferrer"&gt;Adafruit&lt;/a&gt; TFT, and a &lt;a href="https://www.sparkfun.com/products/13266" rel="noopener noreferrer"&gt;K Type Thermocouple breakout from Sparkfun&lt;/a&gt;. I created my own PCBs on my Othermill before getting real PCBs from &lt;a href="https://oshpark.com/" rel="noopener noreferrer"&gt;OSH Park&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I even made a few hacky YouTube videos about the process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frqavngoow2lc7fcmtz5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frqavngoow2lc7fcmtz5k.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm not going to link to those YouTube videos. You're welcome. You can find them if you look hard enough, but don't say I didn't warn you.&lt;/p&gt;

&lt;p&gt;As happens, after a flurry of activity, I put this project on the shelf and moved onto other things. Testing each iteration of the Brew Buddy requires "real world" testing, and believe it or not, there actually is a limit to the amount of beer a human being can drink.&lt;/p&gt;

&lt;p&gt;Late last year, Brew Buddy clawed its way back into my head. Shortly after Particle released their new &lt;a href="https://www.particle.io/mesh/" rel="noopener noreferrer"&gt;3rd generation devices&lt;/a&gt;, the Argon, Boron and Xenon, a little voice ever so softly and gently said &lt;em&gt;"You know, that &lt;a href="https://docs.particle.io/argon/" rel="noopener noreferrer"&gt;Argon&lt;/a&gt; would be great for Brew Buddy. And you can add those new features you've been thinking about."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Powerless to resist the lure of new hardware, I picked the project back up in January. I live streamed a lot of my initial work on &lt;a href="https://twitch.tv/brandonsatrom" rel="noopener noreferrer"&gt;my Twitch channel&lt;/a&gt; and published a &lt;a href="https://blog.particle.io/2019/03/04/upcycling-homebrewing/" rel="noopener noreferrer"&gt;post of the Photon to Argon port on the Particle blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I was sucked back in. &lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Azure DevOps
&lt;/h2&gt;

&lt;p&gt;One of the things I love about hardware projects is that they give me an excuse to explore related topics or concepts that I've been itching to try. The original Brew Buddy, for instance, was a gateway into PCB design, which has become a bit of an obsession for me over the last few years.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1013890175355752448-97" src="https://platform.twitter.com/embed/Tweet.html?id=1013890175355752448"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1013890175355752448-97');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1013890175355752448&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;For this refresh, I really wanted to explore the DevOps side of firmware/IoT development. I'd been hearing a lot of good things about Azure DevOps and the &lt;a href="https://azure.microsoft.com/en-us/services/devops/pipelines/" rel="noopener noreferrer"&gt;new Pipelines&lt;/a&gt; feature, so I decided to give it a try. &lt;/p&gt;

&lt;p&gt;Using Azure Pipelines and the Particle CLI, I was able to quickly automate the process of building BrewBuddy firmware, and releasing binaries, when needed. Here's a quick overview of the steps I took to get this working.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Set up Azure DevOps
&lt;/h2&gt;

&lt;p&gt;To use Azure Pipelines, you need an Azure DevOps account. Microsoft has &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/get-started/index?view=azure-devops" rel="noopener noreferrer"&gt;extensive docs on this process&lt;/a&gt; and I won't repeat them here. Head on over to &lt;a href="https://dev.azure.com" rel="noopener noreferrer"&gt;dev.azure.com&lt;/a&gt; to get yourself all set-up. You'll need to create an Azure DevOps organization before creating a project, and a GitHub account so you can connect your Pipeline to a relevant repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdyjakodny1dom37pgtv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdyjakodny1dom37pgtv.png" alt="My sparse DevOps dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Create your first pipeline
&lt;/h2&gt;

&lt;p&gt;With an Azure DevOps organization created, you're ready to create your first Pipeline. If you're just exploring Pipelines, &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/get-started-yaml?view=azure-devops" rel="noopener noreferrer"&gt;Microsoft has some quick-starts you can clone to try everything out&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;When you create a pipeline, you'll be given two options for authoring: creating the pipeline definition in YAML, or through a visual editor. There are &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/get-started/pipelines-get-started?toc=/azure/devops/pipelines/toc.json&amp;amp;bc=/azure/devops/boards/pipelines/breadcrumb/toc.json&amp;amp;view=azure-devops" rel="noopener noreferrer"&gt;pros and cons to each&lt;/a&gt;. I opted for the YAML approach so that I could version the build process in my &lt;a href="https://github.com/bsatrom/brew-buddy" rel="noopener noreferrer"&gt;Brew Buddy repo&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If you're ready to roll on a real project, the first step is to select a source repo for your pipelines, which can be a repo in GitHub or Azure repos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1l82lq9vn7joawwf5vif.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1l82lq9vn7joawwf5vif.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step is to choose a repository and then select a starter configuration. There are a ton of options here, so you should find something that works with what you're building.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foldv1fojlzb1rmpvtrr8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foldv1fojlzb1rmpvtrr8.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since I'm building a firmware project, you might think I chose the C/C++ with GCC option. Not so! While I could do that, I wanted to do cloud builds with the npm-based &lt;a href="https://docs.particle.io/tutorials/developer-tools/cli/" rel="noopener noreferrer"&gt;Particle CLI&lt;/a&gt;, which means I don't need to install a local GCC toolchain, even in my build environment. Instead, I picked the Node.js option, which gave me a nice pre-configured YAML file ready to be customized.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsa1x6a9sogpdfsgxxhs3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsa1x6a9sogpdfsgxxhs3.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Set-up Triggers and define a VM Pool
&lt;/h2&gt;

&lt;p&gt;The default pipeline will have a few things pre-defined for you, including a single trigger and pool. Triggers define when to run the build pipeline and pools specify in which types of virtual environments you want the pipeline to run. Here are the tweaks I made for my build.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;feature/*&lt;/span&gt;

&lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;vmImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;macOS-10.13'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;By default, builds will trigger on all branches. I changed this slightly to build on both &lt;code&gt;master&lt;/code&gt; and any &lt;code&gt;feature/&lt;/code&gt; branches I create.&lt;/p&gt;

&lt;p&gt;For the VM pool, I am building with &lt;code&gt;macOS&lt;/code&gt; because this closely mirrors my development environment. The Particle CLI is supported across Windows, Mac and Linux, so I didn't really need to change this, but I couldn't resist. We live in a world where Microsoft provides automated build services on macOS in Azure. What a time to be alive.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Use Steps to facilitate dependency installation, builds, and more
&lt;/h2&gt;

&lt;p&gt;In Azure Pipelines, Steps make the bulk of a job. Every pipeline can define one or more steps to install dependencies, run scripts, build artifacts, run tests, and more. For the purposes of this project, there are five steps I needed to take to get from sources to a firmware binary.&lt;/p&gt;
&lt;h3&gt;
  
  
  Install Node.js
&lt;/h3&gt;

&lt;p&gt;First, I need to install Node.js. The template includes this task, but I tweaked it to include Node.js 9.x.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodeTool@0&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;versionSpec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;9.x'&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Node.js'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Install the Particle CLI
&lt;/h3&gt;

&lt;p&gt;With Node.js (and npm) installed, the next step is to globally install the Particle CLI.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;npm install -g particle-cli&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Particle&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CLI'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Login to the Particle CLI
&lt;/h3&gt;

&lt;p&gt;The Particle CLI can perform cloud-based firmware builds, but one must be logged into one's &lt;a href="https://login.particle.io" rel="noopener noreferrer"&gt;Particle account&lt;/a&gt; in order to use this feature. I have an account and credentials that can be used by the pipeline for this job, but I wanted to specify those credentials in a secure manner (as opposed to committing my username and password to source). Thankfully, Azure Pipelines provides support for variables via a Library for every pipeline. I created a group called &lt;code&gt;particle-secrets&lt;/code&gt; and added &lt;code&gt;PARTICLE_USERNAME&lt;/code&gt; and &lt;code&gt;PARTICLE_PASSWORD&lt;/code&gt; variables with the appropriate credentials.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhe4uxm8idkc00xqmrw4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhe4uxm8idkc00xqmrw4.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To use variable groups, I can a reference to the group at the top of my YAML.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;particle-secrets&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Which allows me to reference those variables in the &lt;code&gt;particle login&lt;/code&gt; command.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;particle login --username $(PARTICLE_USERNAME) --password $(PARTICLE_PASSWORD)&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Login&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Particle&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CLI'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Build a firmware binary using the Particle CLI
&lt;/h3&gt;

&lt;p&gt;Once logged in, I can use the &lt;code&gt;particle compile&lt;/code&gt; command to build a binary that targets the Particle Argon and version 0.9.0 of the Device OS firmware.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;particle compile argon --target 0.9.0 brew-buddy-firmware --saveTo brewBuddy.argon.bin&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Build&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Firmware'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Copy the firmware binary to a staging directory
&lt;/h3&gt;

&lt;p&gt;With a binary in hand, I'll copy the &lt;code&gt;.bin&lt;/code&gt; file into a staging directly. This allows me to pick up the binary for the last task.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CopyFiles@2&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sourceFolder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(Build.SourcesDirectory)'&lt;/span&gt;
    &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;brewBuddy.argon.bin'&lt;/span&gt;
    &lt;span class="na"&gt;targetFolder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(Build.ArtifactStagingDirectory)'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  5. Create a GitHub release when merging to master
&lt;/h2&gt;

&lt;p&gt;The steps above run on every check-in and against all my branches to ensure that I can always build firmware and breaking changes aren't committed to my project.&lt;/p&gt;

&lt;p&gt;I do all of my development in &lt;code&gt;feature/&lt;/code&gt; branches, and while I want to continually run builds, I only want to release new firmware when a feature branch is merged to master. Using the &lt;code&gt;condition&lt;/code&gt; statement, I can specify that I only want to run the release task if all prior steps are successful and the source branch is master.  &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="c1"&gt;# GitHub Release&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GithubRelease@0&lt;/span&gt; 
  &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Create&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;GitHub&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Release'&lt;/span&gt;      
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;gitHubConnection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bsatromBB&lt;/span&gt;
    &lt;span class="na"&gt;repositoryName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bsatrom/brew-buddy&lt;/span&gt;
    &lt;span class="na"&gt;tagSource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manual&lt;/span&gt;
    &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$(Build.BuildNumber)&lt;/span&gt; 
    &lt;span class="na"&gt;assets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$(Build.ArtifactStagingDirectory)/*.bin&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;As a part of this final task, the &lt;code&gt;assets&lt;/code&gt; input will grab my firmware binary and include it as a part of the release.&lt;/p&gt;
&lt;h2&gt;
  
  
  6. Run the Pipeline!
&lt;/h2&gt;

&lt;p&gt;With the pipeline in place, the next step it to run it, which can you can do via a check-in, or trigger manually in the DevOps portal. After a few (dozen) tweaks, I was pleased to see rows and rows of green in my builds.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmrfackjjo3y9ydilnmh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmrfackjjo3y9ydilnmh.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And, every PR merged to master results in a new release with an auto-generated change list and a shiny new binary.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8n9niargguyoohulhiwh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8n9niargguyoohulhiwh.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;My full pipeline YAML is available in the &lt;a href="https://github.com/bsatrom/brew-buddy/blob/master/azure-pipelines.yml" rel="noopener noreferrer"&gt;Brew Buddy GitHub repo&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;My experience with Azure Pipelines has been smooth so far. I had a few fits and starts with creating variable groups and getting the GitHub release task right, but no more than one would expect when using a new, unfamiliar service. I've been running the above pipeline for a couple of weeks, and it has been a great addition to my workflow.&lt;/p&gt;

&lt;p&gt;Of course, as a constant tinkerer, there's much more I want to do. Now that I have automated firmware builds, why not use the Particle CLI to do an over-the-air (OTA) firmware update to a dedicated device? After that, why not run automated integration tests using &lt;a href="https://docs.particle.io/reference/device-os/firmware/argon/#cloud-functions" rel="noopener noreferrer"&gt;Particle Variables, Functions and Pub/Sub primitives&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;If all goes well, I'll check back in with another post on that phase of the project in a few weeks.&lt;/p&gt;

&lt;p&gt;Or maybe I'll get distracted by something else. &lt;/p&gt;



&lt;p&gt;To follow my progress on the BrewBuddy and other Particle-powered IoT projects, be sure to &lt;a href="https://twitch.tv/brandonsatrom" rel="noopener noreferrer"&gt;follow me on Twitch&lt;/a&gt; and join me for live streaming fun on Mondays and Thursdays!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/bsatrom" rel="noopener noreferrer"&gt;
        bsatrom
      &lt;/a&gt; / &lt;a href="https://github.com/bsatrom/brew-buddy" rel="noopener noreferrer"&gt;
        brew-buddy
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      hardware, firmware and software projects for the Brew Buddy Project
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Brew Buddy&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://dev.azure.com/brandon0360/BrewBuddy/_build/latest?definitionId=1&amp;amp;branchName=master" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b2071095b1410ab6ec008148906092a8113efb913d451ca686380b0f06acce0f/68747470733a2f2f6465762e617a7572652e636f6d2f6272616e646f6e303336302f4272657742756464792f5f617069732f6275696c642f7374617475732f62736174726f6d2e627265772d62756464793f6272616e63684e616d653d6d6173746572" alt="Build Status"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source for the BrewBuddy project. Contains sources for board hardware/layout, firmware and a 3d printed enclosure.&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/bsatrom/brew-buddy" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>iot</category>
      <category>firmware</category>
      <category>azure</category>
      <category>devops</category>
    </item>
    <item>
      <title>Upcycling an old homebrewing project with a Particle Argon</title>
      <dc:creator>Brandon Satrom</dc:creator>
      <pubDate>Mon, 04 Mar 2019 18:24:59 +0000</pubDate>
      <link>https://forem.com/particle/upcycling-an-old-homebrewing-project-with-a-particle-argon-587k</link>
      <guid>https://forem.com/particle/upcycling-an-old-homebrewing-project-with-a-particle-argon-587k</guid>
      <description>

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DlzyJ4rJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/wmcv1lilznvflmdxkxh8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DlzyJ4rJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/wmcv1lilznvflmdxkxh8.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;New 3rd generation &lt;a href="https://particle.io"&gt;Particle&lt;/a&gt; hardware is here, and there’s a lot to love. I have an old, Photon-based project that I’ve been itching to update and add a few new features to, so I decided to see just how easy it would be to migrate a Photon-based project to the new &lt;a href="https://store.particle.io/products/argon-kit"&gt;Argon&lt;/a&gt;, hardware, firmware and all.&lt;/p&gt;

&lt;p&gt;In addition to this post, you can also go behind the scenes with this build in a series of &lt;a href="https://twitch.tv/brandonsatrom"&gt;Twitch live streams&lt;/a&gt; I’ve recorded and &lt;a href="https://www.youtube.com/channel/UCpYjkSkGOXAMXeZjZkbb-PQ"&gt;posted to YouTube&lt;/a&gt; over the last several weeks. &lt;a href="https://youtu.be/krEzdnlpqC0"&gt;Here’s the first video in the series&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing the Brew Buddy
&lt;/h2&gt;

&lt;p&gt;I’m a home brewer, which is no surprise given that I live in Austin, TX. Not only is homebrewing common in these parts, but every Austin area household must have at least one homebrewer in order to claim city residence.&lt;/p&gt;

&lt;p&gt;That last statement is not true, but it should be.&lt;/p&gt;

&lt;p&gt;I’ve been homebrewing for about eight years, and I’m drawn to it for the same reason many are: not so much for the end product but the process and chemistry of it all. As with cooking and baking, it’s fascinating to take discrete ingredients and—by alchemy—transform them into something enjoyable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current Brew Buddy Specs
&lt;/h2&gt;

&lt;p&gt;As a techie and maker, it should come as no surprise that I’ve explored ways to incorporate technology into my brewing. One example is the Brew Buddy, a connected homebrew monitoring system that tracks wort—the pre-beer mixture of water, grains, malt, and hops — temperatures during the cooking stage of the brewing process. The current version of the project includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Particle Photon as the brains of the project&lt;/li&gt;
&lt;li&gt;One Type-K Thermocouple for measuring wort temperature&lt;/li&gt;
&lt;li&gt;A 2.2 in TFT display for showing temperature readings and a historical temperature graph&lt;/li&gt;
&lt;li&gt;A custom PCB designed in Eagle and fabricated by the fine folks at OSH Park&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rMV4MMq_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/03/PhotonBB.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rMV4MMq_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/03/PhotonBB.png" alt="Brew Buddy Photon"&gt;&lt;/a&gt;The original Brew Buddy build used a Photon with custom PCB.&lt;/p&gt;

&lt;p&gt;The Photon powers and orchestrates the board, while also publishing temperature readings to the Particle cloud so that I can visualize trends from one brew to the next.&lt;/p&gt;

&lt;p&gt;Brew Buddy began — as these things typically do — on a breadboard. Once my design was set, I CNC milled a few PCB revs (my first custom PCBs ever!) and when I was satisfied, contracted a PCB manufacturer for production. That was nearly four years ago, and Brew Buddy is ready for an upgrade.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Dy3ZUJud--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/03/BoardIterations.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Dy3ZUJud--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/03/BoardIterations.png" alt="Various iterations of the Brew Buddy board"&gt;&lt;/a&gt;Various iterations of the Brew Buddy custom PCB that I’ve used over the years.&lt;/p&gt;

&lt;p&gt;I had a few ideas for things to add to the project, like a piezo-based knock sensor to detect when fermentation begins. Particle’s new 3rd generation hardware was the perfect motivation to add those features, design a new board, and explore just how easy it would be to port my project from the Photon to the Argon.&lt;/p&gt;

&lt;p&gt;Spoiler alert: it was so easy! Like hitting that giant red office supply chain button easy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Breadboarding a new prototype
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Iz5G1hFs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/03/FeatureLarge-1024x492.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Iz5G1hFs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/03/FeatureLarge-1024x492.jpg" alt=""&gt;&lt;/a&gt;Prototyping an Argon-powered Brew Buddy began with a breadboard and jumper wires.&lt;/p&gt;

&lt;p&gt;With any new hardware project, even when updating or swapping out components or MCUs, I like to start with a rats nest of jumper wires a breadboard prototype. This an essential step in making sure that I’ve wired everything correctly before taking the time and expense to design and order a board.&lt;/p&gt;

&lt;p&gt;As a bonus, the tangled mess of wires plugged into tiny, nearly invisible slots serves as a pleasant reminder of my ever-increasing age as I squint darkly between wires and try to get everything in the right place.&lt;/p&gt;

&lt;p&gt;Also, turning a mess of wires into copper traces under the solder mask is pretty amazing. It evokes the same feeling like the things in that &lt;a href="https://www.youtube.com/watch?v=MoAGqV7cvqY"&gt;Monday.com commercial&lt;/a&gt; that I find myself not skipping every time I go to YouTube to watch a video about how to beat my kids at Super Smash Bros.&lt;/p&gt;

&lt;h2&gt;
  
  
  My approach to Brew Buddy hardware migration
&lt;/h2&gt;

&lt;p&gt;For the Brew Buddy migration, there were two steps to my breadboard prototype:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Map the existing components (the TFT and Thermocouple) to new pins on the Argon&lt;/li&gt;
&lt;li&gt;Add new connections for the SD Card on the TFT (so I can display bitmaps on the screen) and a thin piezo to function as a “knock sensor.”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All-told, I ended up using 11 GPIO pins on the Argon, up from 9 on the Photon and this was just to get to features packed into the project. There was a bit of trial and error when adding the new features, but I was able to get my prototype up and running in just a few hours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Porting the firmware
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R1D2EDMn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/03/CodeComparison.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R1D2EDMn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/03/CodeComparison.png" alt="Photon to Argon code changes"&gt;&lt;/a&gt;Images showing the difference between the Photon and Argon source code changes — only three lines needed an update.&lt;/p&gt;

&lt;p&gt;With the breadboard prototype all wired up, it was time to port the firmware. I expected that this would consist of three tasks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Update pin-mappings from the Photon to the Argon.&lt;/li&gt;
&lt;li&gt;Update firmware libraries I used, if needed.&lt;/li&gt;
&lt;li&gt;Add libraries and new firmware for the knock sensor and displaying Images on the TFT.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Going into this stage, I wasn’t sure how long each step would take, especially the first two. I was confident that &lt;a href="https://www.particle.io/device-os/"&gt;Device OS&lt;/a&gt; would ensure that the changes needed between boards would be minimal, but I had no idea what “minimal” would entail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your migration may vary…
&lt;/h2&gt;

&lt;p&gt;And with the caveat that YMMV depending on the features and libraries that you’re using for an older project, I was pleasantly surprised to find that, in order to get my existing Photon-based project running on the Argon, I had to change a grand total of THREE lines of code. And all three were GPIO pin mappings for the thermocouple. You can see the &lt;a href="https://github.com/bsatrom/brew-buddy/commit/5024e5ee0dca1f4a5d0951f375b1c2292cdf25f0#diff-059541daca1fa00a0e7e9fa4579ab0a3"&gt;diff here&lt;/a&gt; if you want proof.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_JqqdDTO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/03/BeerTFT2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_JqqdDTO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.particle.io/wp-content/uploads/2019/03/BeerTFT2.png" alt=""&gt;&lt;/a&gt;Testing the Argon-powered Brew Buddy firmware.&lt;/p&gt;

&lt;p&gt;The majority of the work was on the physical pin-mapping side as I was setting up the prototype. Since both the TFT and Thermocouple are SPI devices, I needed to make sure the jumper wires were connected to the Argon’s SPI pins (A6-A8) instead of A3-A5 for the Photon.&lt;/p&gt;

&lt;p&gt;On the firmware libraries front, everything “just worked.” When I first started this project, I was manually including libraries for the TFT and Thermocouple, so my only real step here was adding references to the libraries in my &lt;a href="https://github.com/bsatrom/brew-buddy/commit/7aa10f9ffbea99801ba9d6c5b2b7bed7eb690eb2"&gt;project.properties&lt;/a&gt; file and removing the library source files from my project. Everything compiled on the first try, and I was off to add new features.&lt;/p&gt;

&lt;p&gt;With the new features, I had a bit more work. The piezo is a simple analog sensor and was easy to add to my project. After a bit of trial and error, I was able to calibrate it to detect light movements for fermentation, and I even added Particle’s new sleep mode support so that my device can go offline during the 24-48 hours after cooking is done and wake up when the first sign of fermentation is detected.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;KNOCK_PIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;setBrewMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"brew"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isBrewingMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="c1"&gt;// Start brewing &lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"ferment"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="n"&gt;isBrewingMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="n"&gt;isFermentationMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="n"&gt;fermentationModeStartTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;clearScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;tft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;140&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;printSubheadingLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Waiting for"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;printSubheadingLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Fermentation..."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KNOCK_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CHANGE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"stop"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="c1"&gt;// Stop&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isFermentationMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="kt"&gt;int16_t&lt;/span&gt; &lt;span class="n"&gt;knockVal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;analogRead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KNOCK_PIN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;knockVal&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isFermenting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="n"&gt;isFermenting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;fermentationStartTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;lastKnock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fermentationStartTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;clearScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;tft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;tft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setTextColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ILI9341_YELLOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;tft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setTextSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;tft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Fermentation started"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="n"&gt;tft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setTextColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ILI9341_WHITE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

        &lt;span class="n"&gt;displayFermentationHeading&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Particle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connected&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
        &lt;span class="n"&gt;Particle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fermentation/state"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isBrewingMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="c1"&gt;// Brewing mode logic&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Brew Buddy now with bitmap support
&lt;/h2&gt;

&lt;p&gt;Adding bitmaps to the TFT was a bit more complicated, and included porting the &lt;code&gt;Adafruit_ImageReader&lt;/code&gt; library into the Particle Ecosystem (&lt;a href="https://github.com/bsatrom/Adafruit_ImageReader"&gt;which is public, so please use it!&lt;/a&gt;). With a new library in hand, however, it was just a few more lines of code to get a nice fancy image on the splash screen of my project.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;Adafruit_ILI9341&lt;/span&gt; &lt;span class="n"&gt;tft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Adafruit_ILI9341&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TFT_CS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TFT_DC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TFT_RST&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="n"&gt;Adafruit_ImageReader&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="n"&gt;SdFat&lt;/span&gt; &lt;span class="n"&gt;sd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;tft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TFT_SPEED&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;sd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SD_CS&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;sd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;initErrorHalt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 

  &lt;span class="n"&gt;printSplash&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;printSplash&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ImageReturnCode&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="n"&gt;tft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setRotation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;clearScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="n"&gt;stat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drawBMP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"brew.bmp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;tft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
  &lt;span class="n"&gt;printHeadingTextLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"BrewBuddy"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
  &lt;span class="n"&gt;printHeadingTextLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;APP_VERSION&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;printSubheadingLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Created by"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
  &lt;span class="n"&gt;printSubheadingLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Brandon Satrom"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;I’m pleased to say that, so far, this Photon to Argon port has been a success! With minimal changes to firmware, I was able to take an older project, refresh it, and start adding new functionality.&lt;/p&gt;

&lt;p&gt;And of course, a new working prototype means an excuse to spin a new board and add some cloud-based visualizations of my brews! Stay tuned for part two of this post, where I’ll share the rest of this project and the results of a test brew!&lt;/p&gt;

&lt;p&gt;In the meantime, I’m streaming nearly every step of this project live on Twitch on Tuesdays and Thursdays. Be sure to follow me there, and click the links below for replays of the initial few streams:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://youtu.be/krEzdnlpqC0"&gt;Part 1 – Creating the Prototype and porting firmware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/AQd3qdI9BUE"&gt;Part 2 – Creating a custom PCB in Eagle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/EcKBL6Y56u8"&gt;Part 3 – Adding new firmware for the SD Card reader and Piezo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/OgW8yMLZE3Q"&gt;Part 4 – PCB soldering and assembly&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See you in a few weeks!&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://blog.particle.io/2019/03/04/upcycling-homebrewing/"&gt;Upcycling an old homebrewing project with a Particle Argon&lt;/a&gt; appeared first on &lt;a href="https://blog.particle.io"&gt;Particle Blog&lt;/a&gt;.&lt;/p&gt;


</description>
      <category>howto</category>
      <category>iot</category>
      <category>cpp</category>
      <category>particle</category>
    </item>
  </channel>
</rss>
