<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ particle - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ particle - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 22:25:23 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/particle/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Meet Pyrinas - an IoT Development Kit For Your Particle Xenon ]]>
                </title>
                <description>
                    <![CDATA[ By Jared Wolff This post is a bit lengthy. If you prefer, signup to get the full PDF here. ? After Particle's Mesh deprecation announcement, many have been left to figure out how to deploy their low power sensor networks. There was always the option ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/meet-pyrinas-an-iot-development-kit-for-your-particle-xenon/</link>
                <guid isPermaLink="false">66d85060c15439a8d5631e83</guid>
                
                    <category>
                        <![CDATA[ Bluetooth Low Energy ]]>
                    </category>
                
                    <category>
                        <![CDATA[ embedded systems ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ particle ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 11 Mar 2020 13:49:35 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/03/Copy-of-Particle-Mesh-App-Updates.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jared Wolff</p>
<p>This post is a bit lengthy. If you prefer, <a target="_blank" href="https://www.jaredwolff.com/files/pyrinas-intro/">signup to get the full PDF here.</a> ?</p>
<p>After <a target="_blank" href="https://www.jaredwolff.com/particle-mesh-deprecation-livestream/">Particle's Mesh deprecation announcement</a>, many have been left to figure out how to deploy their low power sensor networks. There was always the option of using <a target="_blank" href="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/">Particle's Built in Bluetooth stack</a> but as it stands today it's not secure.</p>
<p>Previously I had helped form a very simple nRF SDK-based hub and spoke IoT deployment. Unfortunately, it was closed source and the company is no longer around.</p>
<p>So what's a guy to do?</p>
<p>Build another one and make it <em>open. (BSD licensed to be exact!)</em> Open and free for anyone to use adopt and improve upon. Plus if you're building a product that's using the code, <strong>you don't have to share your improvements or proprietary code with anyone.</strong></p>
<p>In this post I'll be talking about how to get started with Pyrinas. It uses Nordic's time tested SDK as a basis for the kernel of the system. The main concept of Pyrinas is to abstract as much IoT cruft away so you can focus on your application.</p>
<p>So without further ado, let's chat about what Pyrinas is and what it isn't.</p>
<h2 id="heading-what-pyrinas-is">What Pyrinas is</h2>
<ul>
<li>Is an embedded "kernel", written in C. It's open and permissive IoT development environment you can use for anything you want. Seriously. It's BSD licensed and can be used in closed source applications.</li>
<li>Using the power of Bluetooth 5.0 Long Range, Pyrinas allows you to communicate with many peripheral devices at one time. Currently Pyrinas has been tested with 3 simultaneous peripheral connections. Theoretically, it can support up to 20 simultaneous connections. (Thanks to <a target="_blank" href="https://cm.nordicsemi.com//Software-and-tools/Software/Bluetooth-Software">Nordic's S140 Softdevice</a>)</li>
<li><p>Pyrinas transports its data in two ways</p>
<ul>
<li>In a familiar string format used by Particle</li>
<li>A custom Protocol Buffer for raw data transmission.</li>
</ul>
<p>That way you have a <strong>choice</strong> of how you want to process and publish your data!</p>
</li>
</ul>
<h2 id="heading-what-pyrinas-isnt">What Pyrinas isn't</h2>
<ul>
<li>Pyrinas is not a RTOS (real time operating system). If you have a need to run multiple threaded applications on embedded, Pyrinas is not for you.</li>
<li>Pyrinas, at this time, does not support Mesh.</li>
<li>An OS for every single kind of Bluetooth SoC on the market. Due to the tight coupling with Nordic's nRF SDK, Pyrinas only works with Nordic's SoCs.</li>
<li>A turnkey solution for IoT. Pyrinas is early on it it's development process. The aim is for it to become a viable option for anyone to develop and publish IoT applications <em>the way they want to.</em> There's no vendor lock in. There's no surprises.</li>
</ul>
<h2 id="heading-things-youll-need">Things you'll need</h2>
<p>There are a few things you'll need in order to get going with Pyrinas.</p>
<ul>
<li>At least 2 Particle Xenons</li>
<li>At least 1 nRF Development board or J-link programmer</li>
<li>Associated USB cables</li>
</ul>
<h2 id="heading-getting-started-with-an-example">Getting started with an example</h2>
<p>Getting started with Pyrinas involves two repositories.</p>
<ul>
<li><a target="_blank" href="https://github.com/pyrinas-iot/pyrinas-os">The OS respository</a></li>
<li><a target="_blank" href="https://github.com/pyrinas-iot/pyrinas-template">The template</a></li>
</ul>
<p>The OS directory has all the source, SDK dependencies and toolchain you need to use Pyrinas.</p>
<p>The template is where you add all your application code. The template provides a starting point for you and your project.</p>
<p>Here's how everything goes together:</p>
<p>Clone the OS directory to some place on your machine:</p>
<pre><code class="lang-shell">git clone https://github.com/pyrinas-iot/pyrinas-os.git --recurse-submodules
</code></pre>
<p>Once complete, change directories to <code>pyrinas-os</code> and run <code>make setup</code></p>
<pre><code class="lang-shell">cd pyrinas-os
make setup
</code></pre>
<p>This will download your toolchain and SDK dependencies.</p>
<p>In order to use OTA DFU, you will need to also generate the DFU key for the process:</p>
<pre><code class="lang-shell">make gen_key
</code></pre>
<p>The files generated by this process will be used later.</p>
<p>Next, we'll want to use the template to make two new projects. In this example we'll have one "hub" and one "sensor." Simply navigate to the <a target="_blank" href="https://github.com/pyrinas-iot/pyrinas-template">template repository</a> and click the <strong>Use this template</strong> button.</p>
<p><img src="https://www.jaredwolff.com/meet-pyrinas-a-new-way-to-use-your-xenon/images//Screen_Shot_2020-03-09_at_5.12.21_PM.png" alt="https://www.jaredwolff.com/meet-pyrinas-a-new-way-to-use-your-xenon/images//Screen_Shot_2020-03-09_at_5.12.21_PM.png" width="730" height="420" loading="lazy"></p>
<p>Then name your new repository. Click the <strong>Create repository from template</strong> button when you're happy with everything.</p>
<p><img src="https://www.jaredwolff.com/meet-pyrinas-a-new-way-to-use-your-xenon/images//Screen_Shot_2020-03-09_at_5.20.15_PM.png" alt="https://www.jaredwolff.com/meet-pyrinas-a-new-way-to-use-your-xenon/images//Screen_Shot_2020-03-09_at_5.20.15_PM.png" width="730" height="449" loading="lazy"></p>
<p>Then clone your repository to the same directory as <code>pyrinas-os</code>. Make sure you replace <code>&lt;your username&gt;</code> and <code>&lt;repo name&gt;</code> with your own.</p>
<pre><code class="lang-shell">cd ..
git clone https://github.com/&lt;your username&gt;/&lt;repo name&gt;.git hub
</code></pre>
<p>After this is done, go back and create a new repository from the template. We'll be using this one for the <em>sensor</em> node.</p>
<p><img src="https://www.jaredwolff.com/meet-pyrinas-a-new-way-to-use-your-xenon/images//Screen_Shot_2020-03-09_at_5.24.15_PM.png" alt="https://www.jaredwolff.com/meet-pyrinas-a-new-way-to-use-your-xenon/images//Screen_Shot_2020-03-09_at_5.24.15_PM.png" width="730" height="449" loading="lazy"></p>
<p>Clone this repository once you're done setting it up in the same place as your <code>hub</code> and <code>pyrinas-os</code> repositories.</p>
<p>Now that we have all our repositories, let's start with our sensor node.</p>
<h3 id="heading-setting-up-the-sensor-node-repository">Setting up the sensor node repository</h3>
<p>Open up the sensor repository using a program like Microsoft's VS Code. If you have the command line shortcuts you can use <code>code</code> to open it from the terminal:</p>
<pre><code class="lang-shell">code sensor
</code></pre>
<p>Before we do anything we'll need to set up the symbolic link to <code>pyrinas-os</code>. Make sure you're in the <code>sensor</code> directory and then run <code>ln -s ../pyrinas-os/</code> using the terminal.</p>
<pre><code class="lang-shell">cd sensor
ln -s ../pyrinas-os/ .
</code></pre>
<p>This allows your project to use all the code, SDK and toolchains within the <code>pyrinas-os</code> repository! As an added bonus you can do this as many times as you want. Have multiple Pyrinas projects? No problem.</p>
<p>Alright! Now, let's check out the Makefile. You'll want to customize some of the definitions within the file:</p>
<pre><code class="lang-makefile"><span class="hljs-comment"># Start: Your configuration!</span>

<span class="hljs-comment"># Set this to the directory of pyrinas-os</span>
<span class="hljs-comment"># If you used a symbolic link this points to</span>
<span class="hljs-comment"># the `pyrinas-os` folder in this repository</span>
OS_DIR := pyrinas-os

<span class="hljs-comment"># This should be the serial number of your Jlink programmer.</span>
<span class="hljs-comment"># To find simply run `jlinkexe`</span>
PROG_SERIAL=1234678

<span class="hljs-comment"># This is your debugger port for Jlink's RTT. If you</span>
<span class="hljs-comment"># have mulitple, you will have to change this on each app</span>
<span class="hljs-comment"># your're using</span>
PROG_PORT=19021

<span class="hljs-comment"># This is where you set your board type. Here are the supported boards:</span>
<span class="hljs-comment"># xenon - Particle Xenon</span>
BOARD=xenon

<span class="hljs-comment"># This is where you can name your app something. Make it specific</span>
APP_FILENAME=pyrinas-template

<span class="hljs-comment"># This determines whether or not you're using debug mode</span>
<span class="hljs-comment"># Comment this out or change to false</span>
DEBUG=true

<span class="hljs-comment"># End: Your Configuration</span>
</code></pre>
<p>For example, you may want to setup your programmer serial. This allows you to use multiple programmers at the same time. (Very helpful in debugging both devices at the same time) To get your programmer's serial plug in your development board and run <code>jlinkexe</code>.</p>
<p>    jlinkexe
    SEGGER J-Link Commander V6.62a (Compiled Jan 31 2020 12:59:22)
    DLL version V6.62a, compiled Jan 31 2020 12:59:05</p>
<p>    Connecting to J-Link via USB...O.K.
    Firmware: J-Link OB-SAM3U128-V2-NordicSemi compiled Jan 21 2020 17:30:48
    Hardware version: V1.00
    S/N: 581758669
    License(s): RDI, FlashBP, FlashDL, JFlash, GDB
    VTref=3.300V</p>
<p>    Type "connect" to establish a target connection, '?' for help
    J-Link&gt;</p>
<p>Find the <strong>S/N</strong> area. This is your serial number!</p>
<p>Alternatively you can look at the sticker on your development kit. It will contain the serial number for your device.</p>
<p>For the <code>PROG_PORT</code> you want to use different ports for each device you're simultaneously debugging. I've found <strong>19021</strong> and <strong>19020</strong> are perfectly good options for most two-device debugging sessions.</p>
<p>The Makefile also includes the ability to choose a board. In our case there's only one option: <code>xenon</code>. Future revisions of Pyrinas will have multiple options.</p>
<p><code>APP_FILENAME</code> is the name of your app. We'll rename ours to <code>pyrinas-sensor</code></p>
<p>Finally, <code>DEBUG</code> is used to halt execution either on an error or restart. For production this should be commented out or set to <code>false</code>. We can leave it as is for now.</p>
<p>The Makefile is also the source for some of the most important commands you'll need during development:</p>
<ul>
<li><code>make build</code> - builds your app.</li>
<li><code>make clean</code> - cleans all remnants of your app.</li>
<li><code>make debug</code> - opens up the <code>jlinkexe</code> debugger console.</li>
<li><code>make erase</code> - erases the chip attached to your programmer.</li>
<li><code>make flash</code> - flashes the current app to your connected device.</li>
<li><code>make flash_softdevice</code> - flashes the soft_device</li>
<li><code>make rtt</code> - opens up the debug console.</li>
<li><code>make ota</code> - generates a zip file used for BLE DFU</li>
</ul>
<h3 id="heading-basic-sensor-node-code">Basic sensor node code</h3>
<p><img src="https://www.jaredwolff.com/meet-pyrinas-a-new-way-to-use-your-xenon/images//Copy_of_Particle_Mesh_App_Updates-3.jpg" alt="https://www.jaredwolff.com/meet-pyrinas-a-new-way-to-use-your-xenon/images//Copy_of_Particle_Mesh_App_Updates-3.jpg" width="730" height="486" loading="lazy"></p>
<p>Now that we have some of the basics out of the way, let's create a very simple application that publishes on a set interval. If you look at <code>app.c</code>, you'll see some code in the <code>setup()</code> function. Let's delete all the commented out code. (We'll use it later for the hub though)</p>
<p>Your code should now look something like:</p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"app.h"</span></span>

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">setup</span><span class="hljs-params">()</span>
</span>{
  BLE_STACK_PERIPH_DEF(init);

  <span class="hljs-comment">// Configuration for ble stack</span>
  ble_stack_init(&amp;init);

  <span class="hljs-comment">// Start advertising</span>
  advertising_start();
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">loop</span><span class="hljs-params">()</span>
</span>{
}
</code></pre>
<p>Now let's create a timer that we'll use to publish on a set interval. Under <code>#include "app.h"</code> create a new timer:</p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"app.h"</span></span>

timer_define(m_sensor_timer);
</code></pre>
<p>We also need to set it up in the <code>setup()</code> function:</p>
<pre><code class="lang-c"><span class="hljs-comment">// Sensor timer</span>
timer_create(&amp;m_sensor_timer, TIMER_REPEATED, sensor_timer_evt);
</code></pre>
<p>You'll notice that <code>timer_create</code> is referring to a event callback called <code>sensor_timer_evt</code>. We'll need to create that guy as well:</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sensor_timer_evt</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-comment">// We'll come back in a sec</span>
}
</code></pre>
<p>The last thing is to start the timer. Let's do that underneath <code>timer_create</code>:</p>
<pre><code class="lang-c"><span class="hljs-comment">// Start</span>
timer_start(&amp;m_sensor_timer, <span class="hljs-number">1000</span>);
</code></pre>
<p>This will start our repeating timer on a 1 second interval.  (<code>timer_start</code> is configured using milliseconds)</p>
<p>Now, inside <code>sensor_timer_evt</code> we'll publish some data. First though we need to make sure that Bluetooth is connected using <code>ble_is_connected</code>.</p>
<pre><code class="lang-c"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> sensor_timer_evt
{
  <span class="hljs-comment">// Check if we're connected</span>
  <span class="hljs-keyword">if</span> (ble_is_connected())
  {
    <span class="hljs-comment">// Sends "ping" with the event name of "data"</span>
    ble_publish(<span class="hljs-string">"data"</span>, <span class="hljs-string">"ping"</span>);
  }
}
</code></pre>
<p>Inside the if statement, we'll use <code>ble_publish</code>. The first argument is the name of the event and the second is the value.</p>
<p>Next, in order to receive messages from the other end we'll need to setup a callback:</p>
<pre><code class="lang-c"><span class="hljs-comment">// Configuration for ble stack</span>
ble_stack_init(&amp;init);

<span class="hljs-comment">// Setup BLE callback</span>
ble_subscribe(<span class="hljs-string">"data"</span>, ble_evt);
</code></pre>
<p>We'll define <code>ble_evt</code> at the top of the file:</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ble_evt</span><span class="hljs-params">(<span class="hljs-keyword">char</span> *name, <span class="hljs-keyword">char</span> *data)</span>
</span>{
  NRF_LOG_INFO(<span class="hljs-string">"%s: %s"</span>, name, data);
}
</code></pre>
<p>In this case we'll use <code>NRF_LOG_INFO</code> to print out the message from the hub.</p>
<p>Finally, in order to get the MAC address easily, we'll have to add a call to print it out in <code>setup()</code>.</p>
<pre><code class="lang-c"><span class="hljs-comment">// Print the address</span>
util_print_device_address();
</code></pre>
<p>In the end your file should look something like this:</p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"app.h"</span></span>

timer_define(m_sensor_timer);

<span class="hljs-comment">// Catch events sent over Bluetooth</span>
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ble_evt</span><span class="hljs-params">(<span class="hljs-keyword">char</span> *name, <span class="hljs-keyword">char</span> *data)</span>
</span>{
  NRF_LOG_INFO(<span class="hljs-string">"%s: %s"</span>, name, data);
}

<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sensor_timer_evt</span><span class="hljs-params">()</span>
</span>{
  <span class="hljs-comment">// Check if we're connected</span>
  <span class="hljs-keyword">if</span> (ble_is_connected())
  {
    <span class="hljs-comment">// Sends "ping" with the event name of "data"</span>
    ble_publish(<span class="hljs-string">"data"</span>, <span class="hljs-string">"ping"</span>);
  }
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">setup</span><span class="hljs-params">()</span>
</span>{
  BLE_STACK_PERIPH_DEF(init);

  <span class="hljs-comment">// Configuration for ble stack</span>
  ble_stack_init(&amp;init);

  <span class="hljs-comment">// Setup BLE callback</span>
  ble_subscribe(<span class="hljs-string">"data"</span>, ble_evt);

  <span class="hljs-comment">// Start advertising</span>
  advertising_start();

  <span class="hljs-comment">// Sensor sensor timer.</span>
  timer_create(&amp;m_sensor_timer, TIMER_REPEATED, sensor_timer_evt);

  <span class="hljs-comment">// Start</span>
  timer_start(&amp;m_sensor_timer, <span class="hljs-number">1000</span>);

  <span class="hljs-comment">// Print the address</span>
  util_print_device_address();
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">loop</span><span class="hljs-params">()</span>
</span>{
}
</code></pre>
<p>Next, we'll program it to some hardware!</p>
<h3 id="heading-flashing-the-basic-sensor-code">Flashing the basic sensor code:</h3>
<p>For this step you'll need to have a Xenon handy. You'll also need a programmer, programming cable and two Micro-B USB cables. Here's a picture of everything connected:</p>
<p><img src="https://www.jaredwolff.com/meet-pyrinas-a-new-way-to-use-your-xenon/images//IMG_4586.jpg" alt="https://www.jaredwolff.com/meet-pyrinas-a-new-way-to-use-your-xenon/images//IMG_4586.jpg" width="730" height="547" loading="lazy"></p>
<p>Once connected and powered run these commands:</p>
<pre><code class="lang-shell">make erase
make flash_softdevice
make flash
make debug
</code></pre>
<p>Then in a separate terminal window run</p>
<pre><code class="lang-shell">make rtt
</code></pre>
<p><code>make debug</code> and <code>make rtt</code> will create a debugging session. You can issue commands in the <code>make debug</code> terminal to control the device as well. For instance, <code>r</code> followed by <code>Enter</code> will restart the device. (By far my most common use case).</p>
<p>If you've flashed everything successfully, your device should start blinking green. That's a good sign!</p>
<p>Additionally, if you take a look at the <code>make rtt</code> side your output should be similar to this:</p>
<p>    ###RTT Client: Connecting to J-Link RTT Server via localhost:19021 ...</p>
<p>    ###RTT Client: Connected.</p>
<p>    SEGGER J-Link V6.62a - Real time terminal output
    J-Link OB-SAM3U128-V2-NordicSemi compiled Jan 21 2020 17:30:48 V1.0, SN=581758669
    Process: JLinkExe
     app_timer: RTC: initialized.
     app: Boot count: 4
     app: Pyrinas started.
     app: Address: 11:22:33:44:55:66</p>
<p>Take note of the address displayed above. We'll need that for the hub code!</p>
<h3 id="heading-setting-up-the-hub-repository">Setting up the hub repository</h3>
<p><img src="https://www.jaredwolff.com/meet-pyrinas-a-new-way-to-use-your-xenon/images//Copy_of_Particle_Mesh_App_Updates-2.jpg" alt="https://www.jaredwolff.com/meet-pyrinas-a-new-way-to-use-your-xenon/images//Copy_of_Particle_Mesh_App_Updates-2.jpg" width="730" height="486" loading="lazy"></p>
<p>If you haven't already, clone your hub repository locally. We'll want to do some of the same steps as we did with the sensor repo like:</p>
<ul>
<li>Setting up the symbolic link</li>
<li>Updating the Makefile<ul>
<li>Setting your <code>PROG_SERIAL</code></li>
<li>Setting <code>PROG_PORT</code> to a port not used by the sensor setup. <code>19020</code> in this case is fine.</li>
<li>Setting <code>APP_FILENAME</code> to <code>pyrinas-hub</code></li>
</ul>
</li>
</ul>
<p>If you need a reminder how any of these steps work, go back and review the earlier section.</p>
<p>Next, we'll want to open <code>app.c</code> and uncomment the central/hub based code. Plus you'll want to remove the default un-commented code. Your <code>setup()</code> should look something like this:</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">setup</span><span class="hljs-params">()</span>
</span>{
  <span class="hljs-comment">// Default config for central mode</span>
  BLE_STACK_CENTRAL_DEF(init);

  <span class="hljs-comment">// Add an addresses to scan for</span>
  <span class="hljs-keyword">ble_gap_addr_t</span> first = {
      .addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC,
      .addr = {<span class="hljs-number">0x81</span>, <span class="hljs-number">0x64</span>, <span class="hljs-number">0x4C</span>, <span class="hljs-number">0xAD</span>, <span class="hljs-number">0x7D</span>, <span class="hljs-number">0xC0</span>}};
  init.config.devices[<span class="hljs-number">0</span>] = first;

  <span class="hljs-keyword">ble_gap_addr_t</span> second = {
      .addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC,
      .addr = {<span class="hljs-number">0x7c</span>, <span class="hljs-number">0x84</span>, <span class="hljs-number">0x9d</span>, <span class="hljs-number">0x32</span>, <span class="hljs-number">0x8d</span>, <span class="hljs-number">0xe4</span>}};
  init.config.devices[<span class="hljs-number">1</span>] = second;

  <span class="hljs-comment">// Increment the device_count</span>
  init.config.device_count = <span class="hljs-number">2</span>;

  <span class="hljs-comment">// Configuration for ble stack</span>
  ble_stack_init(&amp;init);

  <span class="hljs-comment">// Start scanning.</span>
  scan_start();
}
</code></pre>
<p>You'll notice immediately that there are two clients/devices defined here. Let's remove the second one. Should you, in the future, want to connect more devices this is an example of how to do it.</p>
<p><strong>Reminder:</strong> also make sure that you change the <code>init.config.device_count</code> to <code>1</code>.</p>
<p>Then, you'll want to update the <code>.addr</code> field in <code>ble_gap_addr_t first</code> to match the address we got earlier from <code>make rtt</code>:</p>
<pre><code class="lang-c"><span class="hljs-comment">// Add an addresses to scan for</span>
<span class="hljs-keyword">ble_gap_addr_t</span> first = {
    .addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC,
    .addr = {<span class="hljs-number">0x11</span>,<span class="hljs-number">0x22</span>,<span class="hljs-number">0x33</span>,<span class="hljs-number">0x44</span>,<span class="hljs-number">0x55</span>,<span class="hljs-number">0x66</span>}};
init.config.devices[<span class="hljs-number">0</span>] = first;
</code></pre>
<p>The address field uses raw bytes, so it has to be represented that way. Remove the <code>:</code> and place <code>0x</code> in front of each byte. We end up going from <code>11:22:33:44:55:66</code> to <code>{0x11,0x22,0x33,0x44,0x55,0x66}</code></p>
<p>Now before we flash anything, let's also set up the Bluetooth event handler. As with earlier we'll use <code>ble_subscribe</code> to attach an event handler:</p>
<pre><code class="lang-c"><span class="hljs-comment">// Setup BLE callback</span>
ble_subscribe(<span class="hljs-string">"data"</span>, ble_evt);

Then place the function at the top of the file:

<span class="hljs-comment">// Catch events sent over Bluetooth</span>
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ble_evt</span><span class="hljs-params">(<span class="hljs-keyword">char</span> *name, <span class="hljs-keyword">char</span> *data)</span>
</span>{
  NRF_LOG_INFO(<span class="hljs-string">"%s: %s"</span>, name, data);

  ble_publish(<span class="hljs-string">"data"</span>, <span class="hljs-string">"pong"</span>);
}
</code></pre>
<p>You'll notice we're printing out the message using <code>NRF_LOG_INFO</code>. We're also sending a message <em>back</em> to the sensor in the form of <code>ble_publish("data","pong");</code> In other-words we're playing a game of ping-pong between the two devices!</p>
<p>In the end your code should look something like this:</p>
<pre><code class="lang-c"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">"app.h"</span></span>

<span class="hljs-comment">// Catch events sent over Bluetooth</span>
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ble_evt</span><span class="hljs-params">(<span class="hljs-keyword">char</span> *name, <span class="hljs-keyword">char</span> *data)</span>
</span>{
  NRF_LOG_INFO(<span class="hljs-string">"%s: %s"</span>, name, data);

  ble_publish(<span class="hljs-string">"data"</span>, <span class="hljs-string">"pong"</span>);
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">setup</span><span class="hljs-params">()</span>
</span>{
  <span class="hljs-comment">// Default config for central mode</span>
  BLE_STACK_CENTRAL_DEF(init);

  <span class="hljs-comment">// Add an addresses to scan for</span>
  <span class="hljs-keyword">ble_gap_addr_t</span> first = {
      .addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC,
      .addr = {<span class="hljs-number">0x11</span>, <span class="hljs-number">0x22</span>, <span class="hljs-number">0x33</span>, <span class="hljs-number">0x44</span>, <span class="hljs-number">0x55</span>, <span class="hljs-number">0x66</span>}};
  init.config.devices[<span class="hljs-number">0</span>] = first;

  <span class="hljs-comment">// Increment the device_count</span>
  init.config.device_count = <span class="hljs-number">1</span>;

  <span class="hljs-comment">// Configuration for ble stack</span>
  ble_stack_init(&amp;init);

  <span class="hljs-comment">// Setup BLE callback</span>
  ble_subscribe(<span class="hljs-string">"data"</span>, ble_evt);

  <span class="hljs-comment">// Start scanning.</span>
  scan_start();
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">loop</span><span class="hljs-params">()</span>
</span>{
}
</code></pre>
<p><strong>Reminder:</strong> make sure you set <code>ble_gap_addr_t first</code> or the two devices will not connect!</p>
<p>To program, connect the Xenon to program as you did before. We'll flash it using the same methods as before:</p>
<pre><code class="lang-shell">make erase
make flash_softdevice
make flash
make debug
</code></pre>
<p>Then in a separate terminal window run</p>
<pre><code class="lang-shell">make rtt
</code></pre>
<p>Then take a look at each of the <code>make rtt</code> screens. There should be some output! For the hub it should look something like this:</p>
<p>    Process: JLinkExe
     app: Boot count: 4
     app: Pyrinas started.
     ble_m_central: Connected to handle 0x0
     ble_m_central: Protobuf Service discovered
     app: data: ping
     app: data: ping</p>
<p>And the sensor side like this:</p>
<p>    Process: JLinkExe
     app_timer: RTC: initialized.
     app: Boot count: 4
     app: Pyrinas started.
     app: Address: 11:22:33:44:55:66
     ble_m_periph: Notifications enabled!
     app: data: pong
     app: data: pong</p>
<p>The ping and pong messages should continue until you stop them. Awesome! If you get any warnings like this one:</p>
<p>    Unable to write. Notifications not enabled!</p>
<p>Use the reset button on either of the devices. This should fix the problem.</p>
<p><strong>Side note:</strong> the pairing process for Bluetooth is inherently <strong><em>insecure</em></strong>. Once the pairing process is complete though, the devices are secure. (With the caveat that no one was sniffing the pairing process!) There may be improvements on security in the future.</p>
<p><strong>Congrats! ?</strong>If you've made it this far, you've deployed your first Pyrinas hub and sensor client! </p>
<p>For more information about what Pyrinas can do you should check out the header files under <code>pyrinas-os/include/</code>. Also, Pyrinas can do anything that you'd normally be able to do with Nordic's SDK. <a target="_blank" href="https://infocenter.nordicsemi.com/topic/struct_sdk/struct/sdk_nrf5_latest.html?cp=7_1">Nordic's Infocenter</a> is a great resource for learning more about what the SDK has to offer.</p>
<h2 id="heading-what-does-the-future-hold-for-pyrinas">What does the future hold for Pyrinas?</h2>
<p><img src="https://www.jaredwolff.com/meet-pyrinas-a-new-way-to-use-your-xenon/images//Copy_of_Particle_Mesh_App_Updates-5.jpg" alt="https://www.jaredwolff.com/meet-pyrinas-a-new-way-to-use-your-xenon/images//Copy_of_Particle_Mesh_App_Updates-5.jpg" width="730" height="486" loading="lazy"></p>
<p>All future tasks for Pyrinas are shared openly on the <a target="_blank" href="https://github.com/pyrinas-iot/pyrinas-os/projects">Github Repo.</a> Here are some of the high level improvements on the roadmap:</p>
<ul>
<li>Particle Boron + LTE support - That's right! Cellular will be coming to Pyrinas. As of this writing, the first board to support Pyrinas LTE will be Particle's Boron.</li>
<li>MQTT (over TLS) and HTTPS support - Once we have cellular, we need something to communicate with. That's where MQTT and HTTPS come in. They're some of the most popular protocols for IoT today.</li>
<li>Built in remote OTA support - As it stands today, devices programmed with Pyrinas uses Nordic's Secure Bootloader. That means they can be updated over the air by a computer or cellphone nearby. This isn't sustainable for long term deployments though!
Instead, you will be able to push updates to Pyrinas devices over the Cloud. Yup. No reason to get off your couch, you can deploy your updates from anywhere.</li>
<li>Dynamic configuration and management - adding and removing devices from a Pyrinas system currently takes some effort. In future revisions, it will be easier to add and remove devices on the fly. This allows for remote device management with zero headaches.</li>
<li>Support for pre-certified modules and other development boards based on Nordic's nRF52840. Currently the Xenon is the only supported board. Development boards aren't great for full production though. Stay tuned for support for pre-certified modules from vendors like <a target="_blank" href="https://www.fanstel.com/bluenor-summaries">Fanstel</a> and more..</li>
<li>Support for more development environments. Currently Pyrinas supports Mac <em>only</em>.</li>
</ul>
<h3 id="heading-star-and-watch">Star and Watch!</h3>
<p>This is only the tip of the iceberg! Stay tuned for more updates and make you you star and watch <a target="_blank" href="https://github.com/pyrinas-iot/pyrinas-os">the repository</a>.</p>
<p>Or, better yet, looking to help out? Contributions are welcome!</p>
<p><strong>You can read other articles on my blog, <a target="_blank" href="https://www.jaredwolff.com/meet-pyrinas-a-new-way-to-use-your-xenon/">jaredwolff.com</a></strong></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Develop Particle IoT Apps Using NativeScript ]]>
                </title>
                <description>
                    <![CDATA[ By Jared Wolff If you're developing any type of IoT product, inevitably you'll need some type of mobile app. While there are easy ways, they're not for production use. In this tutorial, we'll talk about the basics of Particle app development. You'll ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-develop-particle-iot-apps-using-nativescript/</link>
                <guid isPermaLink="false">66d8504f29e30bc0ad47757b</guid>
                
                    <category>
                        <![CDATA[ iot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ NativeScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ particle ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 27 Jan 2020 17:42:47 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/01/NativeScript---Particle.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jared Wolff</p>
<p>If you're developing any type of IoT product, inevitably you'll need some type of mobile app. While <a target="_blank" href="https://www.jaredwolff.com/create-a-cross-platform-app-using-blynk/">there are easy ways</a>, they're not for production use.</p>
<p>In this tutorial, we'll talk about the basics of Particle app development. You'll learn about some of the many app frameworks you can take advantage of. Plus there's libraries, tricks, and tools along the way to make your life a lot easier.</p>
<h2 id="heading-app-frameworks">App Frameworks</h2>
<p>Sometimes it's dang near irritating to program multiple applications natively. You see, Swift (or Objective C ?) and Java aren't terrible at first glance (well, maybe except for Obj-C ?). But when you're resource constrained, you have to figure out a new game plan. That's where App Frameworks come in.</p>
<p>These frameworks allow an app developer to write, build and test cross platform apps. In some cases, the frameworks convert your app into native code. That means that they run as fast and as well as one written in Swift or Java.</p>
<p>I did the research and as of January 2020, here are some of the most supported frameworks:</p>
<ul>
<li><a target="_blank" href="https://github.com/framework7io/framework7">Framework7</a></li>
<li><a target="_blank" href="https://flutter.dev/">Flutter</a></li>
<li><a target="_blank" href="https://www.nativescript.org/">NativeScript</a></li>
<li><a target="_blank" href="https://github.com/facebook/react-native">ReactNative</a></li>
<li><a target="_blank" href="https://github.com/ionic-team/ionic">Ionic</a></li>
<li><a target="_blank" href="https://cordova.apache.org/">Cordova</a> / <a target="_blank" href="https://phonegap.com/">PhoneGap</a></li>
<li><a target="_blank" href="https://github.com/meteor/meteor">Meteor</a></li>
<li><a target="_blank" href="https://dotnet.microsoft.com/apps/xamarin">Xamarin</a></li>
</ul>
<p>The list goes on for days.</p>
<p>I've used a few of these frameworks in the past. I've built a Meteor app which (surprisingly) worked. In the end I had to pick one though. What did I go with?</p>
<p><strong>NativeScript.</strong></p>
<p>For the most part, NativeScript's documentation and on-boarding experience is fantastic. Not only can you preview your app inside an emulator but you can load it directly to your phone too!</p>
<p><img src="https://www.jaredwolff.com/how-to-develop-particle-iot-apps-using-nativescript/images/Apple_iPhone_6s_Gold_-__status-b1ad9325-8e81-4ee0-b72a-687b62adec29.png" alt="images/Apple_iPhone_6s_Gold_-__status-b1ad9325-8e81-4ee0-b72a-687b62adec29.png" width="730" height="605" loading="lazy"></p>
<p>One of the cool things about NativeScript is that it supports TypeScript. TypeScript is a superset of JavaScript with some extra wiz-bang features. </p>
<p>Unlike other languages, JavaScript technically has no types. If you've done any Particle development you likely know what a type is. We're talking about <code>int</code>, <code>String</code>, <code>float</code> and more. i.e. they're directives to to make sure your JavaScript code stays consistent.</p>
<p>NativeScript is also compatible with most major JavaScript web frameworks. This includes <a target="_blank" href="https://vuejs.org/">Vue.Js</a> and <a target="_blank" href="https://angular.io/">Angular</a>.</p>
<p>I've only noticed one major drawback thus far: the mobile preview mode (<code>tns preview</code> command) does not pay well with native libraries. If you have some native platform specific libraries, you'll have to use the emulator or a device (if you have one).</p>
<p>If you're gung-ho and you <em>want</em> to build multiple apps in their respective languages, the more power to you. There is an advantage over the above frameworks: tried and true Particle SDKs.</p>
<h2 id="heading-available-libraries-amp-sdks">Available Libraries &amp; SDKs</h2>
<p>Particle has gone out of their way to make app development a little easier. This is thanks to the massive development work that has gone into their own SDKs. Yup, gone are the days you have to write manual HTTP request handlers.</p>
<p>Here's a link to both the iOS and Android SDKs:</p>
<ul>
<li><a target="_blank" href="https://docs.particle.io/reference/SDKs/ios/">iOS</a></li>
<li><a target="_blank" href="https://docs.particle.io/reference/SDKs/android/">Android</a></li>
</ul>
<p>Though we won't be covering them here, they reflect all the potential calls that you can make using the <a target="_blank" href="https://docs.particle.io/reference/device-cloud/api/">Cloud API.</a></p>
<p>Speaking of Cloud API, Particle has also developed a <a target="_blank" href="https://docs.particle.io/reference/device-cloud/api/">Node.js</a> library as well. As you can imagine, you can use this for your server side code or JavaScript based app frameworks. Sadly, it doesn't work with NativeScript. Frameworks that use a <a target="_blank" href="https://www.tutorialspoint.com/android/android_webview_layout.htm">WebView</a> should be more compatible.</p>
<p>In the case of this tutorial, we'll be mostly focusing on the Cloud API. This way you have a good understanding of the overall system. It may seem intimidating but if you do it right, you'll get the hang of it real fast.</p>
<h2 id="heading-making-api-calls">Making API Calls</h2>
<p>In NativeScript you can't use libraries like <code>[request](https://github.com/request/request)</code>. (Which happens to be the library Particle's very own <a target="_blank" href="https://github.com/dmiddlecamp">DMC</a> used in the <a target="_blank" href="https://github.com/particle-iot/particle-cli">CLI</a> — DMC if you're reading this, Hi!) You'll have to use the provided <a target="_blank" href="https://docs.nativescript.org/ns-framework-modules/http">HTTP</a> module. </p>
<p>If you scroll all the way to the <a target="_blank" href="https://docs.nativescript.org/ns-framework-modules/http#http-post">bottom of that page</a>, you'll see a fully fledged <code>POST</code> example. I'll reproduce it here but with some Particle specific changes:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Create form post data</span>
<span class="hljs-keyword">var</span> data = <span class="hljs-keyword">new</span> FormData();
data.append(<span class="hljs-string">"name"</span>, <span class="hljs-string">"update"</span>);
data.append(<span class="hljs-string">"data"</span>, <span class="hljs-string">"It's hammer time!"</span>);
data.append(<span class="hljs-string">"private"</span>, <span class="hljs-string">"true"</span>);
data.append(<span class="hljs-string">"access_token"</span>, _token);

<span class="hljs-comment">// Configure the httpModule</span>
<span class="hljs-keyword">return</span> httpModule
    .request({
        url: <span class="hljs-string">`https://api.particle.io/v1/devices/events`</span>,
        method: <span class="hljs-string">"POST"</span>,
        content: data
    })
    .then(
        <span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
            <span class="hljs-keyword">const</span> result = response.content.toJSON();
            <span class="hljs-built_in">console</span>.log(result);
        },
        <span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
            <span class="hljs-keyword">if</span> (e) <span class="hljs-built_in">console</span>.log(e);
        }
    );
</code></pre>
<p>The above is an example of what's equivalent to <code>Particle.publish</code> in DeviceOS. Let's break down the parts.</p>
<p>First of all, one of the main gotchas of Particle's Web API is the data format. I first expected that they use JSON but I was sorely wrong. After actually <em>reading</em> the documentation I realized that most POST requests were actually <code>application/x-www-form-urlencoded</code>. That means when you submit data, it's the equivalent to hitting the submit button on an HTML form.</p>
<p>Fortunately, there is an easy way to assemble form data in Node/JavaScript. We can use the <code>FormData()</code> object. Take a look at the above. There should be some familiar parameter names in the <code>data.append</code> calls.</p>
<p><code>"name"</code> refers to the name of the event you're publishing to.</p>
<p><code>"data"</code> refers to the string formatted data that you're publishing.</p>
<p><code>"private"</code> dictates whether or not you want to broadcast this data to the whole Particle world, or just your little corner of it.</p>
<p><code>"access_token"</code> is a token that you can generate in order to make these API calls. Without a token though, you're dead in the water.</p>
<h3 id="heading-getting-a-token">Getting a Token</h3>
<p>Where do we get this elusive <code>access_token</code>?</p>
<p>At first I had no idea.</p>
<p>I created an OAuth user and secret in the console. That lead to a dead end. Fiddled around with different API calls and settings. Nothing. Then it hit me like a ton of bricks. There's an <code>access_token</code> attached to the curl request on every device page!</p>
<p>Open up any device, click the little console button near <em>Events.</em> A popup with instructions an a URL will pop up. Copy the text after <code>access_token=</code>. That is your <code>access_token</code>! See below:</p>
<p><img src="https://www.jaredwolff.com/how-to-develop-particle-iot-apps-using-nativescript/images/Screen_Shot_2020-01-25_at_8.55.21_AM.png" alt="images/Screen_Shot_2020-01-25_at_8.55.21_AM.png" width="730" height="298" loading="lazy"></p>
<p>You can use this token to make calls to the Particle API. This can be to subscribe, publish, write to a function, read variables and more.</p>
<h3 id="heading-through-the-command-line">Through the command line</h3>
<p>That's nice and everything but how the heck can you <em>programmatically</em> generate one? One way is with the command line.</p>
<p><code>particle token create</code> is the name of the command you need to know about. When you run it, you'll be prompted to login. (Also enter your Authenticator code if you use one.) Then the command line will spit out a shiny new <code>access_token</code> you can use with the API!</p>
<h3 id="heading-through-the-api-itself">Through the API itself</h3>
<p>If you couldn't guess, <code>particle token create</code> is a <a target="_blank" href="https://github.com/particle-iot/particle-cli/blob/20d02afc7b72ade0e79d4f4ec724ec6cce9fff1b/src/lib/api-client.js#L192">frontend to a raw API call</a>. You can make these API calls directly too. Here's what it looks like in NativeScript.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Create form post data</span>
<span class="hljs-keyword">var</span> data = <span class="hljs-keyword">new</span> FormData();
data.append(<span class="hljs-string">"username"</span>, <span class="hljs-string">"jaredwolff"</span>);
data.append(<span class="hljs-string">"password"</span>, <span class="hljs-string">"this is not my password"</span>);
data.append(<span class="hljs-string">"grant_type"</span>, <span class="hljs-string">"password"</span>);
data.append(<span class="hljs-string">"client_name"</span>, <span class="hljs-string">"user"</span>);
data.append(<span class="hljs-string">"client_secret"</span>, <span class="hljs-string">"client_secret_here"</span>);

<span class="hljs-comment">// Configure the httpModule</span>
<span class="hljs-keyword">return</span> httpModule
    .request({
        url: <span class="hljs-string">`https://api.particle.io/v1/oauth/token`</span>,
        method: <span class="hljs-string">"POST"</span>,
        content: data
    })
    .then(
        <span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
            <span class="hljs-keyword">const</span> result = response.content.toJSON();
            <span class="hljs-built_in">console</span>.log(result);
        },
        <span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
            <span class="hljs-keyword">if</span> (e) <span class="hljs-built_in">console</span>.log(e);
        }
    );
</code></pre>
<p>This call <em>may</em> get more complicated. Mostly in the case if you have two factor authorization setup. It's well worth it when you figure it all out. After all, no one wants to manually create auth tokens if they don't have to!</p>
<p>Now you're ready to write and read from your devices. There's one thing though that may trip you up. Subscribing to events can be troublesome with a regular HTTP client. So much so that if you try to do it with NativeScript's HTTP client, it will lock up and never return. Luckily there is a way to handle these special HTTP calls.</p>
<h2 id="heading-server-sent-what">Server Sent What?</h2>
<p>Server Sent Events (SSE for short) is an HTTP/S subscription functionality. It allows you to connect to a SSE end point and continuously listen for updates. It's a similar web technology to what companies use for push notifications. It does require some extra functionality under the hood though...</p>
<h3 id="heading-sse-library">SSE Library</h3>
<p>After much head scratching and searching I stumbled upon <code>nativescript-sse</code>. It looked simple enough that I could start using immediately. More problems arose when I tried to use it though.</p>
<p>First, it turns out you can't use the library in <code>tns preview</code> mode. The alternative is to use <code>tns run ios --emulator</code> or use <code>tns run ios</code> with your iPhone connected to your computer. The non-emulator command will automatically deliver your prototype app.</p>
<p><strong>Side note:</strong> I had already set up my phone in Xcode. You may have to do this yourself before <code>tns run ios</code> is able to find and deploy to your phone.</p>
<p>Secondly, once I got the library working, I noticed I would get some very nasty errors. The errors seemed to happen whenever a new message from Particle came along. </p>
<p>Turns out the underlying Swift library for iOS <a target="_blank" href="https://github.com/inaka/EventSource/issues/89">had fixed this last year.</a> So I took it upon myself to figure out how to upgrade the NativeScript plugin. I'll save you the time to say that it can be a pain and there is a learning curve!</p>
<p>Fortunately after some hacking I got something working. More instructions on how to compile the plugin are in the <a target="_blank" href="https://github.com/jaredwolff/nativescript-sse">README</a>. Alternatively, you can download a pre-built one on the <a target="_blank" href="https://github.com/jaredwolff/nativescript-sse/releases/tag/v4.0.3">Release page of the repository.</a></p>
<p>Download the <code>.tgz</code> file to wherever you like. Then, you can add it using <code>tns plugin add</code>. The full command looks like this:</p>
<pre><code>tns plugin add path/to/plugin/file.tgz
</code></pre><p>You can check to make sure the library is installed by running <code>tns plugin list</code></p>
<pre><code>**jaredwolff$ tns plugin list
<span class="hljs-attr">Dependencies</span>:
┌─────────────────────┬──────────────────────────────────────────────────────────────────────────────────┐
│ Plugin              │ Version                                                                          │
│ @nativescript/theme │ ~<span class="hljs-number">2.2</span><span class="hljs-number">.1</span>                                                                           │
│ nativescript-sse    │ file:../../Downloads/nativescript-sse/publish/package/nativescript-sse<span class="hljs-number">-4.0</span><span class="hljs-number">.3</span>.tgz │
│ tns-core-modules    │ ~<span class="hljs-number">6.3</span><span class="hljs-number">.0</span>                                                                           │
└─────────────────────┴──────────────────────────────────────────────────────────────────────────────────┘
Dev Dependencies:
┌──────────────────────────┬─────────┐
│ Plugin                   │ Version │
│ nativescript-dev-webpack │ ~<span class="hljs-number">1.4</span><span class="hljs-number">.0</span>  │
│ typescript               │ ~<span class="hljs-number">3.5</span><span class="hljs-number">.3</span>  │
└──────────────────────────┴─────────┘
<span class="hljs-attr">NOTE</span>:
If you want to check the dependencies <span class="hljs-keyword">of</span> installed plugin use npm view &lt;pluginName&gt; grep dependencies
If you want to check the dev dependencies <span class="hljs-keyword">of</span> installed plugin use npm view &lt;pluginName&gt; grep devDependencies**
</code></pre><p>Once installed, invoking the library takes a few steps. Here's an example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { SSE } <span class="hljs-keyword">from</span> <span class="hljs-string">"nativescript-sse"</span>;

sse = <span class="hljs-keyword">new</span> SSE(
            <span class="hljs-string">"https://api.particle.io/v1/events/blob?access_token=&lt;your access token&gt;"</span>,
            {}

<span class="hljs-comment">// Add event listener</span>
sse.addEventListener(<span class="hljs-string">"blob"</span>);

<span class="hljs-comment">// Add callback</span>
sse.events.on(<span class="hljs-string">"onMessage"</span>, <span class="hljs-function"><span class="hljs-params">data</span>=&gt;</span>{
    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> do stuff with your event data here!</span>
    <span class="hljs-built_in">console</span>.log(data);
});

<span class="hljs-comment">// Connect if not already</span>
sse.connect();
</code></pre>
<p>First you need to import and create an instance of the library. When you create the instance, you will have to enter the URL that you want to use. </p>
<p>In this case we'll be doing the equivalent of <code>Particle.subscribe()</code>. It should look something similar to the above: <code>https://api.particle.io/v1/events/&lt;your event name&gt;?access_token=&lt;your access token&gt;</code>. </p>
<p>Replace <code>&lt;your event name&gt;</code> and <code>&lt;your access token&gt;</code> with the name of your event and your freshly created token!</p>
<p>Then you set up the library to listen for the event you care about. In this case <code>blob</code> is the event I most care about.</p>
<p>Then make sure you configure a callback! That way you can get access to the data when <code>blob</code> does come along. I've made a <code>TODO</code> note where you can access said data.</p>
<p>Finally, you can connect using the <code>.connect()</code> method. If you don't connect, SSE will not open a session and you'll get no data from Particle.</p>
<p>Placement of the code is up to you but from the examples it looks like within the <code>constructor()</code> of your model is a good place.(<a target="_blank" href="https://github.com/jaredwolff/nativescript-sse/blob/master/demo/app/main-view-model.ts">https://github.com/jaredwolff/nativescript-sse/blob/master/demo/app/main-view-model.ts</a>)</p>
<h3 id="heading-other-examples">Other Examples</h3>
<p>If you're curious how to use SSE in other places I have another great example: Particle's CLI.</p>
<p>Particle uses the <code>[request](https://github.com/request/request)</code> library to handle SSE events in the app. Whenever you call <code>particle subscribe blob</code> it invokes a <code>getStreamEvent</code> further inside the code.  You can <a target="_blank" href="https://github.com/particle-iot/particle-cli/blob/master/src/lib/api-client.js#L862">check it out here.</a> The <code>request</code> library has more information on streaming <a target="_blank" href="https://github.com/request/request#streaming">here</a>.</p>
<h2 id="heading-more-resources">More resources</h2>
<p>This is but the tip of the iceberg when it comes to connecting with Particle's API. Particle has some great documentation (as always) you can check out. Here are some important links:</p>
<ul>
<li><a target="_blank" href="https://docs.particle.io/reference/device-cloud/api/">API documentation</a></li>
<li><a target="_blank" href="https://docs.particle.io/reference/SDKs/javascript/">Javascript SDK</a></li>
<li><a target="_blank" href="https://docs.particle.io/reference/SDKs/ios/">iOS SDK</a></li>
<li><a target="_blank" href="https://docs.particle.io/reference/SDKs/android/">Android SDK</a></li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this post we've talked about app frameworks, NativeScript, NativeScript plugins and Server Sent Events. Plus all the Particle related things so you can connect your NativeScript app to Particle's API. </p>
<p>I hope you've found this quick tutorial useful. If you have any questions feel free to leave a comment or <a target="_blank" href="https://www.jaredwolff.com/contact/">send me a message</a>. Also be sure to check out my <a target="_blank" href="https://www.jaredwolff.com/the-ultimate-guide-to-particle-mesh/">newly released guide</a>. It has content just like this all about Particle's ecosystem.</p>
<p>Until next time!</p>
<p><strong>This post was originally from</strong> <a target="_blank" href="https://www.jaredwolff.com/how-to-develop-particle-iot-apps-using-nativescript/"><strong>https://www.jaredwolff.com/how-to-develop-particle-iot-apps-using-nativescript/</strong></a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Particle Argon For Location Tracking ]]>
                </title>
                <description>
                    <![CDATA[ By Jared Wolff Ever want to add presence or location tracking to a project? Frustrated by the solutions (or lack thereof)? Do not worry, you're not the only one! In this post you'll learn how to implement a very basic tracking and notification applic... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-particle-argon-for-location-tracking/</link>
                <guid isPermaLink="false">66d850584540581f6454411c</guid>
                
                    <category>
                        <![CDATA[ Bluetooth Low Energy ]]>
                    </category>
                
                    <category>
                        <![CDATA[ hardware ]]>
                    </category>
                
                    <category>
                        <![CDATA[ particle ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 09 Sep 2019 13:20:06 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/09/Copy-of-Copy-of-Flow.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jared Wolff</p>
<p>Ever want to add presence or location tracking to a project? Frustrated by the solutions (or lack thereof)?</p>
<p>Do not worry, you're not the only one!</p>
<p>In this post you'll learn how to implement a very basic tracking and notification application. We'll be using a Particle Argon and a Tile Mate.</p>
<p>By the end you'll be able to tell when the Tile is present or not. Plus we'll use Pushover to send push notifications to the devices of your choosing.</p>
<p>Let's get going!</p>
<p><strong>Note</strong> before we get started, this post is <strong>lengthy</strong>. <a target="_blank" href="https://www.jaredwolff.com/files/how-to-location-tracking-using-particle-mesh-pdf/">You can download the PDF version so you can save and view it later.</a></p>
<h2 id="heading-initial-investigation">Initial investigation</h2>
<p>The idea of using a Tile wasn't obvious at first glance. Ideally, using a phone seemed to make more sense. Unfortunately, this wasn't as a viable option. It would require some more research and the creation of a Bluetooth iOS app.</p>
<p>So, the idea of using a phone was out.</p>
<p>Then I thought, "What devices <em>do</em> advertise all the time?"</p>
<p>That is what led me down the path of a tracker like Tile.</p>
<p>After it arrived there was some customary testing. First stop, the Tile application.</p>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/iphone7gold_portrait-2-2b6bcb7b-0f91-4578-a2db-034853565b09.png" alt="Screenshot of Tile App" width="730" height="730" loading="lazy"></p>
<p>I was able to connect and use the device. I even made it play a catchy tune. ?</p>
<p>Then, I moved on to using one of the Bluetooth scanner apps. I scrolled through all the results and Bingo. There was the Tile!</p>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/iphone7gold_portrait-466803ef-57d9-498c-8656-2c274bf7fe8d.png" alt="NRFConnect Scan Results" width="730" height="730" loading="lazy"></p>
<p>I even waited a few hours and checked it again. I wanted to make sure it didn't go to sleep after a while. Turns out, it's always advertising. As far as I can tell, about every 8 seconds.</p>
<p>All of this testing lead to one conclusion: it could be easily used for presence detection.</p>
<p>The next step in the process was trying to figure out how to get it working with an Argon.</p>
<h2 id="heading-advertising">Advertising</h2>
<p>As we had gathered in the previous step, we know that the Tile is advertising about every 8 seconds. That means it should be easily scanned for using any device including an Argon, Zenon or Boron.</p>
<p>For this example I suggest you use an Argon. This is because Bluetooth and Mesh share the same radio. When scanning for the Tile, the Xenon connected to Mesh would often miss the advertising packets. This would lead to false negatives (and frustration!).</p>
<p>Along the same lines, you'll want to make <strong>sure your Argon is connected to no mesh network.</strong> You can remove it using the CLI. Connect your device to your computer and run the following command:</p>
<pre><code class="lang-bash">particle mesh remove &lt;device name/ID&gt;
</code></pre>
<p>Make sure that you replace <strong></strong> with your device's name or ID.</p>
<p>Alright, back to the good stuff.</p>
<p>Advertising can have a few different purposes in Bluetooth. Typically though, it marks the beginning of the pairing phase. That way other devices know that the advertising device is available.</p>
<p>Additionally, the advertising device will indicate what services it has. We can use this knowledge to  filter out devices that don't match.</p>
<p>For example, here's a screenshot of the services available on the Tile device:</p>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/Apple_iPhone_6s_Gold-c1f1d0da-7aba-410a-97b4-3cbebc933208.png" alt="Service information using Light Blue" width="730" height="730" loading="lazy"></p>
<p>When scanning we'll double check that the device we're connecting to has the service UUID of <code>0xfeed</code>.</p>
<p>Before we get deep into Bluetooth land though, let's set up our app for debugging using the Logger.</p>
<h2 id="heading-logging">Logging</h2>
<p>In this tutorial we'll be using the Logger. It allows you to display log messages from your app using <code>particle serial monitor</code>.</p>
<p>One of the cooler features about the logger is the idea of message hierarchy. This allows you, the designer, to selectively mute messages that may not be necessary.</p>
<p>For example, if you have messages used for debugging. You could remove them or comment them out. Or, you could increase the <code>LOG_LEVEL</code> so they're effectively ignored.</p>
<p>Here are the logging levels which are available in <code>logging.h</code> in Particle's device-os repository:</p>
<pre><code class="lang-c++"><span class="hljs-comment">// Log level. Ensure log_level_name() is updated for newly added levels</span>
<span class="hljs-keyword">typedef</span> <span class="hljs-keyword">enum</span> LogLevel {
    LOG_LEVEL_ALL = <span class="hljs-number">1</span>, <span class="hljs-comment">// Log all messages</span>
    LOG_LEVEL_TRACE = <span class="hljs-number">1</span>,
    LOG_LEVEL_INFO = <span class="hljs-number">30</span>,
    LOG_LEVEL_WARN = <span class="hljs-number">40</span>,
    LOG_LEVEL_ERROR = <span class="hljs-number">50</span>,
    LOG_LEVEL_PANIC = <span class="hljs-number">60</span>,
    LOG_LEVEL_NONE = <span class="hljs-number">70</span>, <span class="hljs-comment">// Do not log any messages</span>
    <span class="hljs-comment">// Compatibility levels</span>
    DEFAULT_LEVEL = <span class="hljs-number">0</span>,
    ALL_LEVEL = LOG_LEVEL_ALL,
    TRACE_LEVEL = LOG_LEVEL_TRACE,
    LOG_LEVEL = LOG_LEVEL_TRACE, <span class="hljs-comment">// Deprecated</span>
    DEBUG_LEVEL = LOG_LEVEL_TRACE, <span class="hljs-comment">// Deprecated</span>
    INFO_LEVEL = LOG_LEVEL_INFO,
    WARN_LEVEL = LOG_LEVEL_WARN,
    ERROR_LEVEL = LOG_LEVEL_ERROR,
    PANIC_LEVEL = LOG_LEVEL_PANIC,
    NO_LOG_LEVEL = LOG_LEVEL_NONE
} LogLevel;
</code></pre>
<p>Cool, log levels. But how do we use them?</p>
<p>We can use them by invoking one of these functions:</p>
<p><code>Log.trace</code>, <code>Log.info</code>, <code>Log.warn</code>, <code>Log.error</code>.</p>
<p>For example:</p>
<pre><code class="lang-c++">Log.trace(<span class="hljs-string">"This is a TRACE message."</span>);
</code></pre>
<p>If we set the log level to <code>LOG_LEVEL_INFO</code> we'll only see messages from <code>Log.info</code>, <code>Log.warn</code>, and <code>Log.error</code>. <code>LOG_LEVEL_WARN</code>? Only <code>Log.warn</code> and <code>Log.error</code> will show up. (Hopefully you get the idea.)</p>
<p>To set it up, we'll set the default level to <code>LOG_LEVEL_ERROR</code>. We'll also set the app specific <code>LOG_LEVEL</code> to <code>LOG_LEVEL_TRACE</code>. The end result should look something like this</p>
<pre><code class="lang-c++"><span class="hljs-comment">// For logging</span>
<span class="hljs-function">SerialLogHandler <span class="hljs-title">logHandler</span><span class="hljs-params">(<span class="hljs-number">115200</span>, LOG_LEVEL_ERROR, {
    { <span class="hljs-string">"app"</span>, LOG_LEVEL_TRACE }, <span class="hljs-comment">// enable all app messages</span>
})</span></span>;
</code></pre>
<p>This way we don't get spammed with DeviceOS log messages. Plus, we get all the applicable messages from the app itself.</p>
<p>By the way, if you want to set your device to a single <code>LOG_LEVEL</code> you can set it up like this:</p>
<pre><code class="lang-c++"><span class="hljs-function">SerialLogHandler <span class="hljs-title">logHandler</span><span class="hljs-params">(LOG_LEVEL_INFO)</span></span>;
</code></pre>
<p>As you continue your journey using Particle's DeviceOS you'll soon realize how handy it can be. Now, let's move on to the good stuff!</p>
<h2 id="heading-setting-it-up">Setting it up</h2>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/Screen_Shot_2019-09-06_at_9-a04e6802-ec22-4036-8ace-6150a532979b.50.41_PM.png" alt="Device-os Release Page" width="730" height="614" loading="lazy"></p>
<p>First, we'll want to make sure we're using the correct version of DeviceOS. Any version after 1.3 will have Bluetooth. You can get the <a target="_blank" href="https://www.jaredwolff.com/how-to-upgrade-particle-mesh-device-os/">instructions here</a>.</p>
<p>Next we'll want to start scanning for the Tile. We'll want do do this in the <code>loop()</code> function at a specified interval. We'll use a <code>millis()</code> timer in this case:</p>
<pre><code class="lang-c++"><span class="hljs-comment">// Scan for devices</span>
<span class="hljs-keyword">if</span>( (millis() &gt; lastSeen + TILE_RE_CHECK_MS) ){
    BLE.scan(scanResultCallback, <span class="hljs-literal">NULL</span>);
}
</code></pre>
<p>Make sure you define <code>lastSeen</code> at the top of the file like so:</p>
<pre><code class="lang-c++"><span class="hljs-keyword">system_tick_t</span> lastSeen = <span class="hljs-number">0</span>;
</code></pre>
<p>We'll use it to track the last time the Tile has been "seen". i.e. when the last time the Argon saw an advertising packet from the Tile.</p>
<p><code>TILE_RE_CHECK_MS</code> can be defined as</p>
<pre><code class="lang-c++"><span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> TILE_RE_CHECK_MS 7500</span>
</code></pre>
<p>This way we're checking, at the very minimum, every 7.5 seconds for advertising packets.</p>
<p>In order to find the Tile device we'll use <code>BLE.scan</code>. When we call it, It will start the scanning process.  As devices are found <code>scanResultCallback</code> will fire.</p>
<p>For now, we can define <code>scanResultCallback</code> at the top of the file:</p>
<pre><code class="lang-c++"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">scanResultCallback</span><span class="hljs-params">(<span class="hljs-keyword">const</span> BleScanResult *scanResult, <span class="hljs-keyword">void</span> *context)</span> </span>{
}
</code></pre>
<p>You notice that it includes a <code>BleScanResult</code>. This will contain the address, RSSI and device name (if available) and available service information. This will come in handy later when we're looking for our Tile device!</p>
<p>Remember, that <code>BLE.scan</code> does not return until scanning has been completed. The default timeout for scanning is 5 seconds. You can change that value using <code>BLE.setScanTimeout()</code>. <code>setScanTimeout</code> takes units in 10ms increments. So, for a 500ms timeout would require a value of 50.</p>
<p>For the case of this app, I'd recommend using a value of 8s (8000ms). You can set it like this:</p>
<pre><code class="lang-c++">BLE.setScanTimeout(<span class="hljs-number">800</span>);
</code></pre>
<p>In this case, the device will scan for as long as it takes the Tile to advertise. That way it's less likely to miss an advertising packet.</p>
<h2 id="heading-handling-scan-results">Handling Scan Results</h2>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/Screen_Shot_2019-09-06_at_11-fa1f684f-246c-474a-8397-e7387692e39b.05.19_PM.png" alt="All const definitions" width="730" height="503" loading="lazy"></p>
<p>Now that we have <code>scanResultCallback</code> lets define what's going on inside.</p>
<p>We first want to get the service information inside the advertising data. The best way is to use <code>scanResult-&gt;advertisingData.serviceUUID</code>. We'll pass in an array of UUIDs what will be copied for our use.</p>
<pre><code class="lang-c++">BleUuid uuids[<span class="hljs-number">4</span>];
<span class="hljs-keyword">int</span> uuidsAvail = scanResult-&gt;advertisingData.serviceUUID(uuids,<span class="hljs-keyword">sizeof</span>(uuids)/<span class="hljs-keyword">sizeof</span>(BleUuid));
</code></pre>
<p>This will populate <code>uuids</code> that way you can iterate over them. <code>uuidsAvail</code> will equal the amount of available UUIDs.</p>
<p>On our case we're looking for a particular UUID. We'll define it a the top of the file:</p>
<pre><code class="lang-c++"><span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> TILE_UUID 0xfeed</span>
</code></pre>
<p>Normally UUIDs are <strong>much</strong> longer. A short UUID like this means it has been reserved or is part of the Bluetooth specification. In either case we'll be checking for it in the same way we would check a 32bit or 128bit version.</p>
<p>For diagnostic reasons we can also print out the device information. In this case the RSSI and the device MAC address is handy:</p>
<pre><code class="lang-c++"><span class="hljs-comment">// Print out mac info</span>
BleAddress addr = scanResult-&gt;address;
Log.trace(<span class="hljs-string">"MAC: %02X:%02X:%02X:%02X:%02X:%02X"</span>, addr[<span class="hljs-number">0</span>], addr[<span class="hljs-number">1</span>], addr[<span class="hljs-number">2</span>], addr[<span class="hljs-number">3</span>], addr[<span class="hljs-number">4</span>], addr[<span class="hljs-number">5</span>]);
Log.trace(<span class="hljs-string">"RSSI: %dBm"</span>, scanResult-&gt;rssi);
</code></pre>
<p>Finally let's set up a loop to see if the device found has the UUID:</p>
<pre><code class="lang-c++"><span class="hljs-comment">// Loop over all available UUIDs</span>
<span class="hljs-comment">// For tile devices there should only be one</span>
<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; uuidsAvail; i++){

    <span class="hljs-comment">// Print out the UUID we're looking for</span>
    <span class="hljs-keyword">if</span>( uuids[i].shorted() == TILE_UUID ) {
        Log.trace(<span class="hljs-string">"UUID: %x"</span>, uuids[i].shorted());

        <span class="hljs-comment">// Stop scanning</span>
        BLE.stopScanning();

        <span class="hljs-keyword">return</span>;
    }
}
</code></pre>
<p>We can easily compare the "shorted" version of the UUID with <code>TILE_UUID</code>. It's a simple integer so no complicated memory compare operations are necessary. So, using <code>if( uuids[i].shorted() == TILE_UUID )</code> works just fine.</p>
<p>You can also use <code>Log.trace</code> to print out diagnostic information. In this case we're using it to print out the <code>shorted()</code> version of the UUID.</p>
<h3 id="heading-test-it">Test It!</h3>
<p>Let's test what we have so far!</p>
<p>Program the app to your Argon. Open the terminal and run <code>particle serial monitor</code> to view the debug messages. Heres an example of what you may see:</p>
<pre><code><span class="hljs-number">0000005825</span> [app] TRACE: MAC: <span class="hljs-number">65</span>:C7:B3:AF:<span class="hljs-number">73</span>:<span class="hljs-number">5</span>C
<span class="hljs-number">0000005827</span> [app] TRACE: RSSI: <span class="hljs-number">-37</span>Bm
<span class="hljs-number">0000005954</span> [app] TRACE: MAC: B3:D9:F1:F0:<span class="hljs-number">5</span>D:<span class="hljs-number">7</span>E
<span class="hljs-number">0000005955</span> [app] TRACE: RSSI: <span class="hljs-number">-62</span>Bm
<span class="hljs-number">0000006069</span> [app] TRACE: MAC: C5:F0:<span class="hljs-number">74</span>:<span class="hljs-number">3</span>D:<span class="hljs-number">13</span>:<span class="hljs-number">77</span>
<span class="hljs-number">0000006071</span> [app] TRACE: RSSI: <span class="hljs-number">-62</span>Bm
<span class="hljs-number">0000006217</span> [app] TRACE: MAC: <span class="hljs-number">65</span>:C7:B3:AF:<span class="hljs-number">73</span>:<span class="hljs-number">5</span>C
<span class="hljs-number">0000006219</span> [app] TRACE: RSSI: <span class="hljs-number">-39</span>Bm
<span class="hljs-number">0000006224</span> [app] TRACE: MAC: B3:D9:F1:F0:<span class="hljs-number">5</span>D:<span class="hljs-number">7</span>E
<span class="hljs-number">0000006225</span> [app] TRACE: RSSI: <span class="hljs-number">-62</span>Bm
<span class="hljs-number">0000006296</span> [app] TRACE: MAC: D7:E7:FE:<span class="hljs-number">0</span>C:A5:C0
<span class="hljs-number">0000006298</span> [app] TRACE: RSSI: <span class="hljs-number">-60</span>Bm
<span class="hljs-number">0000006299</span> [app] TRACE: UUID: feed
</code></pre><p>Notice how the message includes <code>TRACE</code> and also <code>[app]</code>? That means it's a trace message originating from the application code. Handy right?</p>
<p>This code does get spammy quick, especially if you're in an environment with lots of advertising Bluetooth devices. If you're Tile is on and running eventually you'll  see a message <code>UUID: feed</code>. That means your Argon found the Tile!</p>
<p>Next we'll use the onboard Mode button to "program" the Tile's address to memory. That way we can filter out all the devices we don't care about.</p>
<h2 id="heading-add-device-on-button-push">Add Device On Button Push</h2>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/Screen_Shot_2019-09-06_at_11-c1b2b96d-3a1b-45b5-bf5f-5fa7824c80d0.06.04_PM.png" alt="System event handler" width="730" height="503" loading="lazy"></p>
<p>First we need to figure out how to monitor the Mode button. The best bet, according to the documentation is to use <code>System.on</code>.</p>
<pre><code class="lang-c++">System.on(button_click, eventHandler);
</code></pre>
<p>The first argument is the name of the system event. In our case it's <code>button_click</code>. The second argument is an event handler function. We'll call it <code>eventHandler</code> for now.</p>
<p>Now let's create <code>eventHandler</code></p>
<pre><code class="lang-c++"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">eventHandler</span><span class="hljs-params">(<span class="hljs-keyword">system_event_t</span> event, <span class="hljs-keyword">int</span> duration, <span class="hljs-keyword">void</span>* )</span>
</span>{

}
</code></pre>
<p><strong>Important:</strong> you can't use the <code>Log</code> function inside <code>eventHandler</code>. An easy way to test it is to toggle the LED on D7. Let's set it up!</p>
<p>Initialize the LED in <code>setup()</code></p>
<pre><code class="lang-c++"><span class="hljs-comment">// Set LED pin</span>
pinMode(D7,OUTPUT);
</code></pre>
<p>Then we can add this inside <code>eventHandler</code></p>
<pre><code class="lang-c++"><span class="hljs-keyword">if</span>( event == button_click ) {
    <span class="hljs-keyword">if</span>( digitalRead(D7) ) {
        digitalWrite(D7,LOW);
    } <span class="hljs-keyword">else</span> {
        digitalWrite(D7,HIGH);
    }
}
</code></pre>
<p>We can then write to D7 (the onboard blue LED). We can even use <code>digitalRead</code> to read what the state of the LED is. It will respond with <code>HIGH</code> or <code>LOW</code> depending on the situation.</p>
<p>Load the firmware onto the device and we'll have nice control over the blue LED!</p>
<p>In the next section, we'll use the Mode button to put the device into a "learning" mode. This will allow us to do a one touch setup with the target Tile device.</p>
<h2 id="heading-storing-address-to-eeprom">Storing Address to EEPROM</h2>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/Screen_Shot_2019-09-06_at_11-8cf61301-8e85-4d65-a2aa-fd37175194f5.07.24_PM.png" alt="Storing to EEPROM" width="730" height="503" loading="lazy"></p>
<p>In this next step we'll store the address of the Tile into EEPROM. That way when the device is restarted or loses power we'll still be able to identify the Tile later on.</p>
<p>There is one lingering question though. How do we get it to save the address in the first place?</p>
<p>By monitoring the button press, we can put the device into a "learning" mode. The device will scan for a Tile, and save the address if it finds one.</p>
<p>First let's add a conditional within <code>if( uuids[i].shorted() == TILE_UUID )</code>:</p>
<pre><code class="lang-c++"><span class="hljs-comment">// If we're in learning mode. Save to EEPROM</span>
<span class="hljs-keyword">if</span>( isLearningModeOn() ) {
    searchAddress = scanResult-&gt;address;
    EEPROM.put(TILE_EEPROM_ADDRESS, searchAddress);
    setLearningModeOff();
}
</code></pre>
<p>We'll use the status of D7 as a way of knowing we're in "learning mode". We do this by reading D7 using <code>digitalRead(D7)</code>. Let's create a function that makes this more clear:</p>
<pre><code class="lang-c++"><span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">isLearningModeOn</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> (digitalRead(D7) == HIGH);
}
</code></pre>
<p>We can also replace the <code>digitalWrite(D7,LOW);</code> and <code>digitalWrite(D7,HIGH);</code> with similar functions. That way it's more straight forward what we're doing.</p>
<pre><code class="lang-c++"><span class="hljs-comment">// Set "Learning mode" on</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">setLearningModeOn</span><span class="hljs-params">()</span> </span>{
    digitalWrite(D7,HIGH);
}

<span class="hljs-comment">// Set "Learning mode" off</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">setLearningModeOff</span><span class="hljs-params">()</span> </span>{
    digitalWrite(D7,LOW);
}
</code></pre>
<p>Then, we assign a global variable <code>searchAddress</code> as the scan result. We setup <code>searchAddress</code> like this at the top of the file:</p>
<pre><code class="lang-c++">BleAddress searchAddress;
</code></pre>
<p>Next we want to save it to non-volatile memory using <code>EEPROM.put</code>. <code>TILE_EEPROM_ADDRESS</code> is defined as <code>0xa</code>. You can define  <code>TILE_EEPROM_ADDRESS</code> to use whatever memory address tickles your fancy. Here's the full definition placed at the top of the file.</p>
<pre><code class="lang-c++"><span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> TILE_EEPROM_ADDRESS 0xa</span>
</code></pre>
<p>Finally, we turn off the LED and "learning mode" using <code>setLearningModeOff()</code></p>
<p>Every time a device is found we'll use <code>millis()</code> to set <code>lastSeen</code>. Additionally, we can track the last RSSI using <code>lastRSSI</code>. It's a cheap way to to know approximately how close the device is. We'll use <code>scanResult-&gt;rssi</code> to get this information and set it to the <code>lastRSSI</code> variable.</p>
<p>Overall, your changes should look something like this:</p>
<pre><code class="lang-c++">...

<span class="hljs-comment">// Print out the UUID we're looking for</span>
<span class="hljs-keyword">if</span>( uuids[i].shorted() == TILE_UUID ) {
    Log.trace(<span class="hljs-string">"UUID: %x"</span>, uuids[i].shorted());

    <span class="hljs-comment">// If we're in learning mode. Save to EEprom</span>
    <span class="hljs-keyword">if</span>( isLearningModeOn() ) {
        searchAddress = scanResult-&gt;address;
        EEPROM.put(TILE_EEPROM_ADDRESS, searchAddress);
        setLearningModeOff();
    }

    <span class="hljs-comment">// Save info</span>
    lastSeen = millis();
    lastRSSI = scanResult-&gt;rssi;

    <span class="hljs-comment">// Stop scanning</span>
    BLE.stopScanning();

    <span class="hljs-keyword">return</span>;
}
</code></pre>
<p>Before this function, we can filter out devices that don't match our <code>searchAddress</code>. Add the following before <code>if( uuids[i].shorted() == TILE_UUID )</code>:</p>
<pre><code class="lang-c++"><span class="hljs-comment">// If device address doesn't match or we're not in "learning mode"</span>
<span class="hljs-keyword">if</span>( !(searchAddress == scanResult-&gt;address) &amp;&amp; !isLearningModeOn() ) {
    <span class="hljs-keyword">return</span>;
}
</code></pre>
<p>This will skip over devices that don't match. It will only proceed if the address matches or we're in "learning mode".</p>
<p>Now, in order for us to load <code>searchAddress</code> on startup, we'll have to load it from flash. Add this line to your <code>setup():</code></p>
<pre><code class="lang-c++">EEPROM.get(TILE_EEPROM_ADDRESS, searchAddress);
</code></pre>
<p>Then, check to make sure the address is valid. It won't be valid if all the bytes are <code>0xFF</code>:</p>
<pre><code class="lang-c++"><span class="hljs-comment">// Warning about address</span>
<span class="hljs-keyword">if</span>( searchAddress == BleAddress(<span class="hljs-string">"ff:ff:ff:ff:ff:ff"</span>) ) {
    Log.warn(<span class="hljs-string">"Place this board into learning mode"</span>);
    Log.warn(<span class="hljs-string">"and keep your Tile near by."</span>);
}
</code></pre>
<p>We should be able to "teach" our Argon the address of our Tile. Let's test it out!</p>
<h3 id="heading-test-it-1">Test it.</h3>
<p>Now if we compile and run the app, notice how there's no more log output? We have to "teach" the Tile address to the Particle Device. So, hit the mode button. The blue LED should turn on.</p>
<p>Once your Tile has been found the LED will turn off and you'll see some output on the command line. Similar to what we've seen before:</p>
<pre><code><span class="hljs-number">0000006296</span> [app] TRACE: MAC: D7:E7:FE:<span class="hljs-number">0</span>C:A5:C0
<span class="hljs-number">0000006298</span> [app] TRACE: RSSI: <span class="hljs-number">-60</span>Bm
<span class="hljs-number">0000006299</span> [app] TRACE: UUID: feed
</code></pre><p>The device has been committed to memory!</p>
<p>You can also check if it's still saved after a reset. Hit the <strong>reset</strong> button and check for the same output as above. If it's showing up, we're still good!</p>
<h2 id="heading-update-the-cloud">Update the Cloud</h2>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/Screen_Shot_2019-09-06_at_11-34eb3433-edb7-4b57-b3ca-3be935bba026.07.53_PM.png" alt="Publishing to the Particle cloud" width="730" height="503" loading="lazy"></p>
<p>Finally let's set up a function called <code>checkTileStateChanged</code>. We'll use it to check for changes to the state of the Tile on a regular interval.</p>
<pre><code class="lang-c++"><span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">checkTileStateChanged</span><span class="hljs-params">( TilePresenceType *presence )</span> </span>{

}
</code></pre>
<p>The main purpose of this function is to compare the <code>lastSeen</code> variable with the "timeout" duration. In our case, our timeout duration is <code>TILE_NOT_HERE_MS</code> which should be set to</p>
<pre><code class="lang-c++"><span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> TILE_NOT_HERE_MS 30000</span>
</code></pre>
<p>near the top of your program. There's also two more conditions to look for. One where <code>lastSeen</code> is equal to 0. This is usually because the app hasn't found the Tile yet after startup.</p>
<p>The last case would be if the device has been seen and <code>lastSeen</code> is not 0. So within <code>checkTileStateChanged</code> let's put everything together.</p>
<pre><code class="lang-c++"><span class="hljs-comment">// Check to see if it's here.</span>
<span class="hljs-keyword">if</span>( millis() &gt; lastSeen+TILE_NOT_HERE_MS ) {

} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ( lastSeen == <span class="hljs-number">0</span> ) {

} <span class="hljs-keyword">else</span> {

}

<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
</code></pre>
<p>Now we only want this function to return true <strong>if the state has changed</strong>. So we'll need to take advantage of the <code>TilePresenceType</code> pointer in the agreement.</p>
<p><code>TilePresenceType</code> is simply an enumeration of all the possible states. You can stick it at the top of your file as well. Here it is:</p>
<pre><code class="lang-c++"><span class="hljs-keyword">typedef</span> <span class="hljs-keyword">enum</span> {
    PresenceUnknown,
    Here,
    NotHere
} TilePresenceType;
</code></pre>
<p>You'll also need a global variable that we can pass to the function. Set this at the top of your file as well:</p>
<pre><code class="lang-c++"><span class="hljs-comment">// Default status</span>
TilePresenceType present = PresenceUnknown;
</code></pre>
<p>Now, we can compare at each stage. Does it meet the criteria? Is the state different than the last one? If so, return true.</p>
<p>Remember, we'll want to set <code>presence</code> to the new updated value. So each condition should update the presence value. For example:</p>
<pre><code class="lang-c++">*presence = NotHere;
</code></pre>
<p>Here's what the fully flushed out function looks like:</p>
<pre><code class="lang-c++"><span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">checkTileStateChanged</span><span class="hljs-params">( TilePresenceType *presence )</span> </span>{

    <span class="hljs-comment">// Check to see if it's here.</span>
    <span class="hljs-keyword">if</span>( millis() &gt; lastSeen+TILE_NOT_HERE_MS ) {
        <span class="hljs-keyword">if</span>( *presence != NotHere ) {
            *presence = NotHere;
            Log.trace(<span class="hljs-string">"not here!"</span>);
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        }
    <span class="hljs-comment">// Case if we've just started up</span>
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ( lastSeen == <span class="hljs-number">0</span> ) {
        <span class="hljs-keyword">if</span>( *presence != PresenceUnknown ) {
            *presence = PresenceUnknown;
            Log.trace(<span class="hljs-string">"unknown!"</span>);
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        }
    <span class="hljs-comment">// Case if lastSeen is &lt; TILE_NOT_HERE_MS</span>
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">if</span>( *presence != Here ) {
            *presence = Here;
            Log.trace(<span class="hljs-string">"here!"</span>);
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        }
    }

    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
</code></pre>
<p>We can now use this function in the main loop underneath the timer to start <code>Ble.scan()</code>. We can use it to send a JSON payload. In this case we'll include important information like the Bluetooth Address, <code>lastSeen</code> data, <code>lastRSSI</code> data and a message.</p>
<pre><code class="lang-c++"><span class="hljs-comment">// If we have a change</span>
<span class="hljs-keyword">if</span>( checkTileStateChanged(&amp;present) ) {

}
</code></pre>
<p>We'll use an array of <code>char</code> to get our address in a string format. You can chain together <code>toString()</code> with <code>toCharArray</code> to get what we need.</p>
<pre><code class="lang-c++"><span class="hljs-comment">// Get the address string</span>
<span class="hljs-keyword">char</span> address[<span class="hljs-number">18</span>];
searchAddress.toString().toCharArray(address,<span class="hljs-keyword">sizeof</span>(address));
</code></pre>
<p>An example payload string could look something like this:</p>
<pre><code class="lang-c++"><span class="hljs-comment">// Create payload</span>
status = String::format(<span class="hljs-string">"{\"address\":\"%s\",\"lastSeen\":%d,\"lastRSSI\":%i,\"status\":\"%s\"}"</span>,
    address, lastSeen, lastRSSI, messages[present]);
</code></pre>
<p><code>status</code> is simply a String defined at the top of the file:</p>
<pre><code class="lang-c++"><span class="hljs-comment">// The payload going to the cloud</span>
String status;
</code></pre>
<p>You notice that there's also a variable called <code>messages</code>. This is a static const array of strings. They're mapped to the values from the <code>TilePresenceType</code>. Here's what it looks like</p>
<pre><code class="lang-c++"><span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span> * messages[] {
    <span class="hljs-string">"unknown"</span>,
    <span class="hljs-string">"here"</span>,
    <span class="hljs-string">"not here"</span>
};
</code></pre>
<p>That way <code>PresenceUnknown</code> matches to <code>"unknown"</code>, <code>Here</code> matches to <code>"here"</code>, etc. It's a cheap easy way to associate a string with an enum.</p>
<p>Finally we'll publish and process. This allows us to send the update immediately.</p>
<pre><code class="lang-c++"><span class="hljs-comment">// Publish the RSSI and Device Info</span>
Particle.publish(<span class="hljs-string">"status"</span>, status, PRIVATE, WITH_ACK);

<span class="hljs-comment">// Process the publish event immediately</span>
Particle.process();
</code></pre>
<p>The overall function should look something like this in the end:</p>
<pre><code class="lang-c++"><span class="hljs-comment">// If we have a change</span>
<span class="hljs-keyword">if</span>( checkTileStateChanged(&amp;present) ) {

    <span class="hljs-comment">// Get the address string</span>
    <span class="hljs-keyword">char</span> address[<span class="hljs-number">18</span>];
    searchAddress.toString().toCharArray(address,<span class="hljs-keyword">sizeof</span>(address));

    <span class="hljs-comment">// Create payload</span>
    status = String::format(<span class="hljs-string">"{\"address\":\"%s\",\"lastSeen\":%d,\"lastRSSI\":%i,\"status\":\"%s\"}"</span>,
        address, lastSeen, lastRSSI, messages[present]);

    <span class="hljs-comment">// Publish the RSSI and Device Info</span>
    Particle.publish(<span class="hljs-string">"status"</span>, status, PRIVATE, WITH_ACK);

    <span class="hljs-comment">// Process the publish event immediately</span>
    Particle.process();

}
</code></pre>
<p>Now, let's test it!</p>
<h3 id="heading-testing-it">Testing it!</h3>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/Screen_Shot_2019-09-06_at_11-97c0bda9-1ba1-4c75-8bd7-4db655d35d51.27.35_PM.png" alt="Test results in terminal window" width="730" height="662" loading="lazy"></p>
<p>We can test to make sure our Publish events are occurring without event leaving Particle Workbench. Open a new terminal by going to <strong>View → Terminal.</strong> Then use the following command:</p>
<pre><code class="lang-bash">particle subscribe --device &lt;device_name&gt; &lt;event_name&gt;
</code></pre>
<p>Replace <code>&lt;device_name&gt;</code> with the name or ID of your device.</p>
<p>Replace <code>&lt;event_name&gt;</code> with the name of the event. In our case it's <code>status</code>.</p>
<p>You can then test it all by removing the battery and waiting for the  "not here" alert. Plug the battery back in and you should get a "here" alert.</p>
<p>Here's an example of the output</p>
<pre><code>&gt; particle subscribe --device hamster_turkey status

Subscribing to <span class="hljs-string">"status"</span> <span class="hljs-keyword">from</span> hamster_turkey<span class="hljs-string">'s stream
Listening to: /v1/devices/hamster_turkey/events/status
{"name":"status","data":"{\"address\":\"C0:A5:0C:FE:E7:D7\",\"lastSeen\":40154002,\"lastRSSI\":-82,\"status\":\"not here\"}","ttl":60,"published_at":"2019-09-07T02:29:42.232Z","coreid":"e00fce68d36c42ef433428eb"}
{"name":"status","data":"{\"address\":\"C0:A5:0C:FE:E7:D7\",\"lastSeen\":40193547,\"lastRSSI\":-83,\"status\":\"here\"}","ttl":60,"published_at":"2019-09-07T02:29:50.352Z","coreid":"e00fce68d36c42ef433428eb"}</span>
</code></pre><h2 id="heading-configuring-webhook">Configuring Webhook</h2>
<p>In the last part of this tutorial we'll set up push notifications using a webhook. As mentioned before, we'll use Pushover and their handy API to send push notification(s) to the device(s) of your choice.</p>
<p>Pushover has a fantastically easy API to use. Their application is a Swiss army knife for situations where you don't want to code an app to send push notifications.</p>
<p>The first thing that you'll have to take note is your <strong>user key.</strong> You can get that by logging into Pushover. Note: you'll need to set up an account first if you haven't already.</p>
<p>It should look something like this:</p>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/Screen_Shot_2019-09-03_at_3-e71c60fd-ef57-4e5f-a7a5-e836b36af15e.39.36_PM.png" alt="Pushover main screen" width="730" height="590" loading="lazy"></p>
<p>If you're logged in and don't see this page, click on the <strong>Pushover logo</strong> and that should bring you back.</p>
<p>Next we'll want to create an application. Click on the <strong>Apps &amp; Plugins</strong> at the top of the screen.</p>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/Screen_Shot_2019-09-03_at_3-3144b865-133a-4778-b349-37ebb333ede7.39.42_PM.png" alt="App/Plugins screen in Pushover" width="730" height="590" loading="lazy"></p>
<p>You should then click <strong>Create a New Application.</strong> This will allow us to get an <strong>API Token</strong> that will be needed in the Particle Webhook setup.</p>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/Screen_Shot_2019-09-05_at_11-c5628ee5-3aa9-4e82-b302-051278631a6b.49.21_AM.png" alt="Create a New Application" width="730" height="602" loading="lazy"></p>
<p>Set a name as you see fit. Fill in the description if you want a reminder. <strong>Click the box</strong> and then click <strong>Create Application.</strong></p>
<p>You should go to the next page. Copy and save the <strong>API Token/Key</strong> we'll need this also in a few steps.</p>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/Screen_Shot_2019-09-03_at_3-a9e88ba1-dcb8-4b4d-8f20-a67e70e84ff5.39.50_PM.png" alt="Viewing Application with API key" width="730" height="590" loading="lazy"></p>
<p>Now, let's setup the Webhook. Jump over to <a target="_blank" href="https://console.particle.io/">https://console.particle.io</a> and create a new integration.</p>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/Screen_Shot_2019-09-03_at_3-ef788a5e-710f-4457-9b04-133d4ecf5f94.41.55_PM.png" alt="Particle console creating new Webhook" width="730" height="573" loading="lazy"></p>
<p>We'll set the <strong>Event Name</strong> to <strong>status</strong>.</p>
<p>The <strong>URL</strong> to <strong><a target="_blank" href="https://api.pushover.net/1/messages.json">https://api.pushover.net/1/messages.json</a></strong></p>
<p>Also, if you want to filter by a specific device make sure you select it in the <strong>Device dropdown.</strong></p>
<p>Under <strong>Advanced Settings</strong> we'll finish up by setting a few fields.</p>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/Screen_Shot_2019-09-03_at_3-831e153a-bb8c-4d73-98c4-61a958c9c51a.42.01_PM.png" alt="Setting the token and api key in Particle Webhook" width="730" height="573" loading="lazy"></p>
<p>Create the following fields: <strong>token,</strong> <strong>user</strong>, <strong>title</strong>, and <strong>message</strong>. Then set token to the <strong>API Token</strong> we got earlier. Do the same for the <strong>User Key.</strong></p>
<p>The <strong>title</strong> will show up as the title of your message. Make it whatever makes sense for you.</p>
<p>You can set the <strong>message</strong> as <code>The Tile is currently {{{status}}}. RSSI: {{{lastRSSI}}}</code>.</p>
<p>We are using mustache templates here. They allow you to use the data in the published payload and reformat it to your liking. In our case, we're using them to "fill in the blanks." The <strong>message</strong> once processed would look something like this:</p>
<p><code>The Tile is currently here. RSSI: -77</code></p>
<p>As a side note, i'll be talking more about these templates in <a target="_blank" href="https://www.jaredwolff.com/the-ultimate-guide-to-particle-mesh/">my guide</a>. So stay tuned for that!</p>
<h3 id="heading-test-it-2">Test it</h3>
<p>Once your integration is in place, you can test doing what we did in the earlier step. Remove the battery, and wait for the "not here" message. Put it back and wait for the "here" message.</p>
<p>Here's what it would look like on an iPhone:</p>
<p><img src="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/images/Pushover-58cbd968-ffbe-4aa5-9087-de6f98708715.png" alt="Pushover messages from Particle Cloud" width="730" height="730" loading="lazy"></p>
<p>As you can see, I tested it a bunch! ?</p>
<p>If you've made it this far and everything is working, great work. You now have a Tile tracker for your house, office or wherever.</p>
<h2 id="heading-the-code">The Code</h2>
<p>Looking for the finished code for this example? I would be too! It's <a target="_blank" href="https://github.com/jaredwolff/particle-bluetooth-presence-detection">hosted on Github and is available here</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>As you can imagine, the techniques and technologies used in this article can be used in many ways. Let's summarize some of the key take aways:</p>
<ol>
<li>Using Bluetooth Central to scan for and identify an off-the-shelf Tile device</li>
<li>Storing the Tile identifying information to EEPROM. That way it can be retrieved on startup.</li>
<li>Using our familiar <code>Particle.publish</code> to push updates to the cloud.</li>
<li>Using a Particle Integration Webhook to create push notifications on state change.</li>
</ol>
<p>Now that you have it all working, expand on it, hack it and make it yours. Oh and don't forget to share! I'd love to hear from you. <a target="_blank" href="mailto:hello@jaredwolff.com">hello@jaredwolff.com</a></p>
<p>Like this post? Click one of the share links below and share it with the world. :)</p>
<p><strong>This is a cross post from my blog. <a target="_blank" href="https://www.jaredwolff.com/how-to-location-tracking-using-particle-mesh/">You can check out the original here.</a></strong></p>
<p>Interested in learning more? I'm writing a guide on how to get the most out of the Particle Platform. <a target="_blank" href="https://www.jaredwolff.com/the-ultimate-guide-to-particle-mesh/">Learn more about it here.</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The Ultimate How-to: Build a Bluetooth Swift App With Hardware in 20 Minutes ]]>
                </title>
                <description>
                    <![CDATA[ By Jared Wolff In a previous tutorial, you learned how to add Bluetooth to a Particle Xenon application. That way you could control the onboard RGB LED from a test app like nRF Connect or Light Blue Explorer. In this post, we're going to take it one ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/</link>
                <guid isPermaLink="false">66d85067f6b5e038a1bde7f9</guid>
                
                    <category>
                        <![CDATA[ Bluetooth Low Energy ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ particle ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift Programming ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 13 Aug 2019 14:15:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/08/main.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jared Wolff</p>
<p>In a <a target="_blank" href="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/">previous tutorial</a>, you learned how to add Bluetooth to a Particle Xenon application. That way you could control the onboard RGB LED from a test app like nRF Connect or Light Blue Explorer.</p>
<p>In this post, we're going to take it one step further. We're going to develop a Swift app to control a Particle Mesh RGB led. If all goes well, you should have a working app in about 20 minutes!</p>
<p>Let's get started.</p>
<h3 id="heading-dont-have-time-right-now-to-read-the-full-article">Don't have time right now to read the full article?</h3>
<p><a target="_blank" href="https://www.jaredwolff.com/files/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/">Download the PDF version here.</a></p>
<h2 id="heading-getting-set-up">Getting set up</h2>
<ul>
<li>Install Xcode. <a target="_blank" href="https://developer.apple.com/xcode/resources/">You can download it from the App store here.</a></li>
<li>You'll also need an Apple login. I use my iCloud email. You can create a new account within Xcode if you don't have one yet.</li>
<li>Install the <a target="_blank" href="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/#final-code">RGB example code</a> on a Particle Mesh board.</li>
</ul>
<h2 id="heading-create-the-project">Create the project</h2>
<p>Once everything is installed, let's get to the fun stuff!</p>
<p>Open Xcode and go to <strong>File → New Project.</strong></p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_3-7ef4de80-050c-4fc3-9cf2-8581e16ffe18.10.57_PM.png" alt="Xcode New Project" width="600" height="400" loading="lazy"></p>
<p>Select <strong>Single View App.</strong></p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_3-ef953954-312b-4320-be30-5da186d0902e.11.14_PM.png" alt="New Project Info" width="600" height="400" loading="lazy"></p>
<p>Then update the <strong>Project Name</strong> to be to your liking. I've also changed my organization identifier to <code>com.jaredwolff</code>. Modify it as you see fit!</p>
<p>Select a location to save it.</p>
<p>Next find your <strong>Info.plist.</strong></p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_3-27439ca7-68c5-4890-902d-6c2ee7f31829.13.26_PM.png" alt="Info.plist in Xcocde" width="600" height="400" loading="lazy"></p>
<p>Update <code>info.plist</code> by adding <code>Privacy - Bluetooth Peripheral Usage Description</code></p>
<p>The description I ended up using was <code>App uses Bluetooth to connect to the Particle Xenon RGB Example</code></p>
<p>This allows you to use Bluetooth in your app if you ever want to release it.</p>
<p>Now, let's get everything minimally functional!</p>
<h2 id="heading-minimally-functional">Minimally functional</h2>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Copy_of_Flow-5e62bf38-b399-4bca-9b5b-c63f9716af33.jpg" alt="New section image" width="600" height="400" loading="lazy"></p>
<p>Next, we'll get a minimally functional app to connect and do a services discovery. Most of the action will happen in the <code>ViewController.swift</code>.</p>
<p>Lets first import <code>CoreBluetooth</code></p>
<pre><code class="lang-swift">    <span class="hljs-keyword">import</span> CoreBluetooth
</code></pre>
<p>This allows us to control the Bluetooth Low Energy functionality in iOS. Then let's add both the <code>CBPeripheralDelegate</code> and <code>CBCentralManagerDelegate</code> to the <code>ViewController</code> class.</p>
<pre><code class="lang-swift">    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ViewController</span>: <span class="hljs-title">UIViewController</span>, <span class="hljs-title">CBPeripheralDelegate</span>, <span class="hljs-title">CBCentralManagerDelegate</span> </span>{
</code></pre>
<p>Let's now create local private variables to store the actual central manager and peripheral. We'll set them up further momentarily.</p>
<pre><code class="lang-swift">    <span class="hljs-comment">// Properties</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> centralManager: <span class="hljs-type">CBCentralManager!</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> peripheral: <span class="hljs-type">CBPeripheral!</span>
</code></pre>
<p>In your <code>viewDidLoad</code> function, let's init the <code>centralManager</code></p>
<pre><code class="lang-swift">    centralManager = <span class="hljs-type">CBCentralManager</span>(delegate: <span class="hljs-keyword">self</span>, queue: <span class="hljs-literal">nil</span>)
</code></pre>
<p>Setting <code>delegate: self</code> is important. Otherwise the central state never changes on startup.</p>
<p>Before we get further, let's create a separate file and call it <code>ParticlePeripheral.swift</code>. It can be placed anywhere but I placed it in a separate 'group' called <strong>Models</strong> for later.</p>
<p>Inside we'll create some public variables which contain the UUIDs for our Particle Board. They should look familiar!</p>
<pre><code class="lang-swift">    <span class="hljs-keyword">import</span> UIKit
    <span class="hljs-keyword">import</span> CoreBluetooth

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ParticlePeripheral</span>: <span class="hljs-title">NSObject</span> </span>{

        <span class="hljs-comment">/// MARK: - Particle LED services and charcteristics Identifiers</span>

        <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> particleLEDServiceUUID     = <span class="hljs-type">CBUUID</span>.<span class="hljs-keyword">init</span>(string: <span class="hljs-string">"b4250400-fb4b-4746-b2b0-93f0e61122c6"</span>)
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> redLEDCharacteristicUUID   = <span class="hljs-type">CBUUID</span>.<span class="hljs-keyword">init</span>(string: <span class="hljs-string">"b4250401-fb4b-4746-b2b0-93f0e61122c6"</span>)
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> greenLEDCharacteristicUUID = <span class="hljs-type">CBUUID</span>.<span class="hljs-keyword">init</span>(string: <span class="hljs-string">"b4250402-fb4b-4746-b2b0-93f0e61122c6"</span>)
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> blueLEDCharacteristicUUID  = <span class="hljs-type">CBUUID</span>.<span class="hljs-keyword">init</span>(string: <span class="hljs-string">"b4250403-fb4b-4746-b2b0-93f0e61122c6"</span>)

    }
</code></pre>
<p>Back in <code>ViewController.swift</code> let's piece together the Bluetooth bits.</p>
<h3 id="heading-bluetooth-bits">Bluetooth bits</h3>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Flow-3cb1d250-f9d5-4757-a244-be29bed9dcf6.jpg" alt="Flow diagram for Bluetooth Swift in iOS" width="600" height="400" loading="lazy"></p>
<p>Everything to do with Bluetooth is event based. We'll be defining several functions that handle these events. Here are the important ones:</p>
<p><code>centralManagerDidUpdateState</code> updates when the Bluetooth Peripheral is switched on or off. It will fire when an app first starts so you know the state of Bluetooth. We also start scanning here.</p>
<p>The <code>centralManager</code> <code>didDiscover</code> event occurs when you receive scan results. We'll use this to start a connection.</p>
<p>The <code>centralManager</code> <code>didConnect</code> event fires once the device is connected. We'll start the device discovery here. <strong>Note:</strong> Device discovery is the way we determine what services and characteristics are available. This is a good way to confirm what type of device we're connected to.</p>
<p>The <code>peripheral</code> <code>didDiscoverServices</code> event first once all the services have been discovered. Notice that we've switched from <code>centralManager</code> to <code>peripheral</code> now that we're connected. We'll start the characteristic discovery here. We'll be using the RGB service UUID as the target.</p>
<p>The <code>peripheral</code> <code>didDiscoverCharacteristicsFor</code> event will provide all the characteristics using the provided service UUID. This is the last step in the chain of doing a full device discovery. It's hairy but it only has to be done once during the connection phase!</p>
<h3 id="heading-defining-all-the-bluetooth-functions">Defining all the Bluetooth functions.</h3>
<p>Now that we know what the functions events that get triggered. We'll define them in the logical order that they happen during a connection cycle.</p>
<p>First, we'll define <code>centralManagerDidUpdateState</code> to start scanning for a device with our Particle RGB LED Service. If Bluetooth is not enabled, it will not do anything.</p>
<pre><code class="lang-swift">    <span class="hljs-comment">// If we're powered on, start scanning</span>
        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">centralManagerDidUpdateState</span><span class="hljs-params">(<span class="hljs-number">_</span> central: CBCentralManager)</span></span> {
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"Central state update"</span>)
            <span class="hljs-keyword">if</span> central.state != .poweredOn {
                <span class="hljs-built_in">print</span>(<span class="hljs-string">"Central is not powered on"</span>)
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-built_in">print</span>(<span class="hljs-string">"Central scanning for"</span>, <span class="hljs-type">ParticlePeripheral</span>.particleLEDServiceUUID);
                centralManager.scanForPeripherals(withServices: [<span class="hljs-type">ParticlePeripheral</span>.particleLEDServiceUUID],
                                                  options: [<span class="hljs-type">CBCentralManagerScanOptionAllowDuplicatesKey</span> : <span class="hljs-literal">true</span>])
            }
        }
</code></pre>
<p>Defining the <code>centralManager</code> <code>didDiscover</code> is our next step in the process. We know we've found a device if this event has occurred.</p>
<pre><code class="lang-swift">    <span class="hljs-comment">// Handles the result of the scan</span>
        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">centralManager</span><span class="hljs-params">(<span class="hljs-number">_</span> central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : <span class="hljs-keyword">Any</span>], rssi RSSI: NSNumber)</span></span> {

            <span class="hljs-comment">// We've found it so stop scan</span>
            <span class="hljs-keyword">self</span>.centralManager.stopScan()

            <span class="hljs-comment">// Copy the peripheral instance</span>
            <span class="hljs-keyword">self</span>.peripheral = peripheral
            <span class="hljs-keyword">self</span>.peripheral.delegate = <span class="hljs-keyword">self</span>

            <span class="hljs-comment">// Connect!</span>
            <span class="hljs-keyword">self</span>.centralManager.connect(<span class="hljs-keyword">self</span>.peripheral, options: <span class="hljs-literal">nil</span>)

        }
</code></pre>
<p>So, we stop scanning using <code>self.centralManager.stopScan()</code>. We set the <code>peripheral</code> so it persists through the app. Then we connect to that device using <code>self.centralManager.connect</code></p>
<p>Once connected, we need to double check if we're working with the right device.</p>
<pre><code class="lang-swift">    <span class="hljs-comment">// The handler if we do connect succesfully</span>
        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">centralManager</span><span class="hljs-params">(<span class="hljs-number">_</span> central: CBCentralManager, didConnect peripheral: CBPeripheral)</span></span> {
            <span class="hljs-keyword">if</span> peripheral == <span class="hljs-keyword">self</span>.peripheral {
                <span class="hljs-built_in">print</span>(<span class="hljs-string">"Connected to your Particle Board"</span>)
                peripheral.discoverServices([<span class="hljs-type">ParticlePeripheral</span>.particleLEDServiceUUID])
            }
        }
</code></pre>
<p>By comparing the two peripherals we'll know its the device we found earlier. We'll kick off a services discovery using <code>peripheral.discoverService</code>. We can use <code>ParticlePeripheral.particleLEDServiceUUID</code> as a parameter. That way we don't pick up any services we don't care about.</p>
<p>Once we finish the discovering services, we'll get a <code>didDiscoverServices</code> event. We iterate through all the "available" services. (Though there will only be one!)</p>
<pre><code class="lang-swift">    <span class="hljs-comment">// Handles discovery event</span>
        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">peripheral</span><span class="hljs-params">(<span class="hljs-number">_</span> peripheral: CBPeripheral, didDiscoverServices error: Error?)</span></span> {
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> services = peripheral.services {
                <span class="hljs-keyword">for</span> service <span class="hljs-keyword">in</span> services {
                    <span class="hljs-keyword">if</span> service.uuid == <span class="hljs-type">ParticlePeripheral</span>.particleLEDServiceUUID {
                        <span class="hljs-built_in">print</span>(<span class="hljs-string">"LED service found"</span>)
                        <span class="hljs-comment">//Now kick off discovery of characteristics</span>
                        peripheral.discoverCharacteristics([<span class="hljs-type">ParticlePeripheral</span>.redLEDCharacteristicUUID,
                                                                 <span class="hljs-type">ParticlePeripheral</span>.greenLEDCharacteristicUUID,
                                                                 <span class="hljs-type">ParticlePeripheral</span>.blueLEDCharacteristicUUID], <span class="hljs-keyword">for</span>: service)
                        <span class="hljs-keyword">return</span>
                    }
                }
            }
        }
</code></pre>
<p>By this point this is the third time we're checking to make sure we have the correct service. This becomes more handy later when there are many characteristics and many services.</p>
<p>We call <code>peripheral.discoverCharacteristics</code> with an array of UUIDs for the characteristics we're looking for. They're all the UUIDs that we defined in <code>ParticlePeripheral.swift</code>.</p>
<p>Finally, we handle the <code>didDiscoverCharacteriscsFor</code> event. We iterate through all the available characteristics. As we iterate we compare with the ones we're looking for.</p>
<pre><code class="lang-swift">    <span class="hljs-comment">// Handling discovery of characteristics</span>
        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">peripheral</span><span class="hljs-params">(<span class="hljs-number">_</span> peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?)</span></span> {
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> characteristics = service.characteristics {
                <span class="hljs-keyword">for</span> characteristic <span class="hljs-keyword">in</span> characteristics {
                    <span class="hljs-keyword">if</span> characteristic.uuid == <span class="hljs-type">ParticlePeripheral</span>.redLEDCharacteristicUUID {
                        <span class="hljs-built_in">print</span>(<span class="hljs-string">"Red LED characteristic found"</span>)
                    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> characteristic.uuid == <span class="hljs-type">ParticlePeripheral</span>.greenLEDCharacteristicUUID {
                        <span class="hljs-built_in">print</span>(<span class="hljs-string">"Green LED characteristic found"</span>)
                    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> characteristic.uuid == <span class="hljs-type">ParticlePeripheral</span>.blueLEDCharacteristicUUID {
                        <span class="hljs-built_in">print</span>(<span class="hljs-string">"Blue LED characteristic found"</span>);
                    }
                }
            }
        }
</code></pre>
<p>At this point we're ready to do a full device discovery of our Particle Mesh device. In the next section we'll test what we have to make sure things are working ok.</p>
<h2 id="heading-testing-our-minimal-example">Testing our minimal example</h2>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Flow-6-744bf855-fd7c-403b-b07f-dfc0c191b6af.jpg" alt="Section image about testing" width="600" height="400" loading="lazy"></p>
<p>Before we get started, if you run into trouble I've put some troubleshooting steps in the <a target="_blank" href="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/#troubleshooting">footnotes</a>.</p>
<p><strong>To test, you'll have to have an iPhone with Bluetooth Low Energy.</strong> Most modern iPhones have it. The last iPhone not to have it I believe was either the iPhone 4 or 3Gs. (so you're likely good)</p>
<p>First, plug it into your computer.</p>
<p>Go to the top by the play and stop buttons. Select your target device. In my case I chose my phone (<strong>Jared's iPhone</strong>). You can also use an iPad.</p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-09_at_4-d04de709-6000-4161-bd12-7347a70d6e1e.37.27_PM.png" alt="Select device type" width="600" height="400" loading="lazy"></p>
<p>Then you can hit <strong>Command + R</strong> or hit that <strong>Play button</strong> to load the app to your phone.</p>
<p>Make sure you have your log tab open. Enable it by clicking the bottom pane button in the top right corner.</p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-09_at_4-8b83ea0a-274f-4a41-a5ff-e80717b41977.38.57_PM.png" alt="Bottom pane in Xcode for logs" width="600" height="400" loading="lazy"></p>
<p>Make sure you have a mesh device setup and running the example code. You can go to <a target="_blank" href="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/#final-code">this post</a> to get it. Remember your Particle Mesh board needs to be running device OS 1.3.0 or greater for Bluetooth to work!</p>
<p>Once both the firmware and app is loaded, let's check the log output.</p>
<p>It should look something like this:</p>
<pre><code>View loaded
Central state update
Central scanning <span class="hljs-keyword">for</span> B4250400-FB4B<span class="hljs-number">-4746</span>-B2B0<span class="hljs-number">-93</span>F0E61122C6
Connected to your Particle Board
LED service found
Red LED characteristic found
Green LED characteristic found
Blue LED characteristic found
</code></pre><p>This means that your Phone has connected, found the LED service! The characteristics also being discovered is important here. Without those we wouldn't be able to send data to the mesh device.</p>
<p>Next step is to create some sliders so we can update the RGB values on the fly.</p>
<h2 id="heading-slide-to-the-left-slide-to-the-right">Slide to the left. Slide to the right.</h2>
<p>Next we're going to add some elements to our <code>Main.storyboard</code>. Open <code>Main.storyboard</code> and click on the <strong>View</strong> underneath <strong>View Controller.</strong></p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_1-7919e3c2-cb72-4297-b9e0-06139a064fec.57.37_PM.png" alt="Updating view in Xcode" width="600" height="400" loading="lazy"></p>
<p>Then click on the <strong>Library</strong> button. (It looks like the old art Apple used for the home button)</p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_1-895d247a-6706-4c39-be04-0bda41195ca6.58.02_PM.png" alt="Library button in Xcode" width="600" height="400" loading="lazy"></p>
<p>You'll get a pop-up with all the choices that you can insert into your app.</p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_1-8b531053-621e-4c14-8086-2ac0ef6e52de.58.31_PM.png" alt="Library pane in Xcode" width="600" height="400" loading="lazy"></p>
<p>Drag three <strong>Labels</strong> and copy three <strong>Sliders</strong> to your view.</p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_1-9c8c6167-2279-4cb7-a37b-c24b8cdd275d.59.39_PM.png" alt="Dragging Labels to Xcode View" width="600" height="400" loading="lazy"></p>
<p>You can double click on the labels and rename them as you go.</p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_1-72573a66-1201-4d08-902d-ea905c91b2bb.59.57_PM.png" alt="Dragging Slider to Xcode View" width="600" height="400" loading="lazy"></p>
<p>If you click and hold, some handy alignment tools will popup. They'll even snap to center!</p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_2-4c7b1627-c55e-4eba-b29a-32915ba41867.00.17_PM.png" alt="Alignment tools in Xcode" width="600" height="400" loading="lazy"></p>
<p>You can also select them all and move them together. We'll align them vertically and horizontally.</p>
<p>In order for them to stay in the middle, let's remove the autoresizing property. Click the <strong>Ruler icon</strong> on the top right. Then click each of the <strong>red bars</strong>. This will ensure that your labels and sliders stay on the screen!</p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_2-f207fae8-7292-4e38-9985-c97444ab4e55.09.39_PM.png" alt="Ruler pane in Xcode" width="600" height="400" loading="lazy"></p>
<p>Next let's click the <strong>Show Assistant Editor</strong> button. (Looks like a Venn diagram)</p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_2-c52c52b8-70b3-426b-9cbe-9df1042f5fb1.00.59_PM.png" alt="Show Assistant Editor button in Xcode" width="600" height="400" loading="lazy"></p>
<p><strong>Note:</strong> make sure that <strong>ViewController.swift</strong> is open in your Assistant Editor.</p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_2-655a4468-4da8-4841-a2dc-1cf8706592e7.17.35_PM.png" alt="Automatic option in Assistant Editor" width="600" height="400" loading="lazy"></p>
<p>Then underneath the <code>/properties</code> section, <strong>Control-click and drag</strong> <strong>the Red Slider</strong> into your code.</p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_2-39480e58-fd92-4ec7-a2db-9e8524019755.01.43_PM.png" alt="Drag slider to code" width="600" height="400" loading="lazy"></p>
<p>Repeat with all the other ones. Make sure you name them something different. Your code should look like this when you're done:</p>
<pre><code class="lang-swift">        <span class="hljs-comment">// Properties</span>
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> centralManager: <span class="hljs-type">CBCentralManager!</span>
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> peripheral: <span class="hljs-type">CBPeripheral!</span>

        <span class="hljs-comment">// Sliders</span>
        <span class="hljs-meta">@IBOutlet</span> <span class="hljs-keyword">weak</span> <span class="hljs-keyword">var</span> redSlider: <span class="hljs-type">UISlider!</span>
        <span class="hljs-meta">@IBOutlet</span> <span class="hljs-keyword">weak</span> <span class="hljs-keyword">var</span> greenSlider: <span class="hljs-type">UISlider!</span>
        <span class="hljs-meta">@IBOutlet</span> <span class="hljs-keyword">weak</span> <span class="hljs-keyword">var</span> blueSlider: <span class="hljs-type">UISlider!</span>
</code></pre>
<p>This allow us to access the value of the sliders.</p>
<p>Next, let's attach the <strong>Value Changed</strong> event to each of the sliders. <strong>Right click</strong> on the <strong>Red Slider in the folder view.</strong></p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_2-b2ffe0a6-709e-433d-9d4c-0f8028bd096c.03.44_PM.png" alt="Drag value changed event to code" width="600" height="400" loading="lazy"></p>
<p>It should give you some options for events. Click and drag the <strong>Value Changed</strong> event to your code. Make sure you name it something that makes sense. I used <strong>RedSliderChanged</strong> for the Red Slider.</p>
<p>Repeat two more times. Your code should look like this at the end of this step:</p>
<pre><code class="lang-swift">        <span class="hljs-meta">@IBAction</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">RedSliderChanged</span><span class="hljs-params">(<span class="hljs-number">_</span> sender: <span class="hljs-keyword">Any</span>)</span></span> {
        }

        <span class="hljs-meta">@IBAction</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">GreenSliderChanged</span><span class="hljs-params">(<span class="hljs-number">_</span> sender: <span class="hljs-keyword">Any</span>)</span></span> {
        }

        <span class="hljs-meta">@IBAction</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">BlueSliderChanged</span><span class="hljs-params">(<span class="hljs-number">_</span> sender: <span class="hljs-keyword">Any</span>)</span></span> {
        }
</code></pre>
<p>I've also selected each of the sliders to and <strong>un-checked Enabled</strong>. That way you can't move them. We'll enable them later on in code.</p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_2-e7e0aca9-224c-4bfb-b482-1d9e58b37947.21.21_PM.png" alt="Disable slider by default" width="600" height="400" loading="lazy"></p>
<p>Also, this is a great time to change the <strong>maximum value to 255</strong>. Also set the default <strong>value from 0.5 to 0.</strong></p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Screen_Shot_2019-08-11_at_2-9bf5618b-f6ac-4aea-9888-7f93a8c75414.55.38_PM.png" alt="Set default value and max value of slider" width="600" height="400" loading="lazy"></p>
<p>Back at the top of the file. Let's create some local variables for each of the characteristics. We'll use these so we can write the slider variables to the Particle Mesh board.</p>
<pre><code class="lang-swift">        <span class="hljs-comment">// Characteristics</span>
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> redChar: <span class="hljs-type">CBCharacteristic?</span>
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> greenChar: <span class="hljs-type">CBCharacteristic?</span>
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> blueChar: <span class="hljs-type">CBCharacteristic?</span>
</code></pre>
<p>Now, let's tie everything together!</p>
<p>In the <code>didDiscoverCharacteristicsFor</code> callback function. Let's assign those characteristics. For example</p>
<pre><code class="lang-swift">    <span class="hljs-keyword">if</span> characteristic.uuid == <span class="hljs-type">ParticlePeripheral</span>.redLEDCharacteristicUUID {
        <span class="hljs-built_in">print</span>(<span class="hljs-string">"Red LED characteristic found"</span>)
        redChar = characteristic
</code></pre>
<p>As we find each characteristic, we can also enable each of the sliders in the same spot.</p>
<pre><code class="lang-swift">            <span class="hljs-comment">// Unmask red slider</span>
            redSlider.isEnabled = <span class="hljs-literal">true</span>
</code></pre>
<p>In the end your <code>didDiscoverCharacteristicsFor</code> should look like:</p>
<pre><code class="lang-swift">    <span class="hljs-comment">// Handling discovery of characteristics</span>
        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">peripheral</span><span class="hljs-params">(<span class="hljs-number">_</span> peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?)</span></span> {
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> characteristics = service.characteristics {
                <span class="hljs-keyword">for</span> characteristic <span class="hljs-keyword">in</span> characteristics {
                    <span class="hljs-keyword">if</span> characteristic.uuid == <span class="hljs-type">ParticlePeripheral</span>.redLEDCharacteristicUUID {
                        <span class="hljs-built_in">print</span>(<span class="hljs-string">"Red LED characteristic found"</span>)

                        redChar = characteristic
                        redSlider.isEnabled = <span class="hljs-literal">true</span>
                    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> characteristic.uuid == <span class="hljs-type">ParticlePeripheral</span>.greenLEDCharacteristicUUID {
                        <span class="hljs-built_in">print</span>(<span class="hljs-string">"Green LED characteristic found"</span>)

                        greenChar = characteristic
                        greenSlider.isEnabled = <span class="hljs-literal">true</span>
                    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> characteristic.uuid == <span class="hljs-type">ParticlePeripheral</span>.blueLEDCharacteristicUUID {
                        <span class="hljs-built_in">print</span>(<span class="hljs-string">"Blue LED characteristic found"</span>);

                        blueChar = characteristic
                        blueSlider.isEnabled = <span class="hljs-literal">true</span>
                    }
                }
            }
        }
</code></pre>
<p>Now, let's update the <code>RedSliderChanged</code> <code>GreenSliderChanged</code> and <code>BlueSliderChanged</code> functions. What we want to do here is update the characteristic associated with the <code>Changed</code> function. I created a separate function called <code>writeLEDValueToChar</code>. We'll pass in the characteristic and the data.</p>
<pre><code class="lang-swift">    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeLEDValueToChar</span><span class="hljs-params">( withCharacteristic characteristic: CBCharacteristic, withValue value: Data)</span></span> {

            <span class="hljs-comment">// Check if it has the write property</span>
            <span class="hljs-keyword">if</span> characteristic.properties.<span class="hljs-built_in">contains</span>(.writeWithoutResponse) &amp;&amp; peripheral != <span class="hljs-literal">nil</span> {

                peripheral.writeValue(value, <span class="hljs-keyword">for</span>: characteristic, type: .withoutResponse)

            }

        }
</code></pre>
<p>Now add a call to <code>writeLEDValueToChar</code> to each of the <code>Changed</code> functions. You will have to cast the value to a <code>Uint8</code>. (The Particle Mesh device expects an unsigned 8-bit number.)</p>
<pre><code class="lang-swift">            <span class="hljs-meta">@IBAction</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">RedSliderChanged</span><span class="hljs-params">(<span class="hljs-number">_</span> sender: <span class="hljs-keyword">Any</span>)</span></span> {
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"red:"</span>,redSlider.value);
            <span class="hljs-keyword">let</span> slider:<span class="hljs-type">UInt8</span> = <span class="hljs-type">UInt8</span>(redSlider.value)
            writeLEDValueToChar( withCharacteristic: redChar!, withValue: <span class="hljs-type">Data</span>([slider]))

        }
</code></pre>
<p>Repeat this for <code>GreenSliderChanged</code> and <code>BlueSliderChanged</code>. Make sure you changed <code>red</code> to <code>green</code> and <code>blue</code> for each!</p>
<p>Finally, to keep things clean, i've also added a function that handles Bluetooth disconnects.</p>
<pre><code class="lang-swift">    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">centralManager</span><span class="hljs-params">(<span class="hljs-number">_</span> central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?)</span></span> {
</code></pre>
<p>Inside, we should reset the state of the sliders to 0 and disable them.</p>
<pre><code class="lang-swift">            <span class="hljs-keyword">if</span> peripheral == <span class="hljs-keyword">self</span>.peripheral {
                <span class="hljs-built_in">print</span>(<span class="hljs-string">"Disconnected"</span>)

                redSlider.isEnabled = <span class="hljs-literal">false</span>
                greenSlider.isEnabled = <span class="hljs-literal">false</span>
                blueSlider.isEnabled = <span class="hljs-literal">false</span>

                redSlider.value = <span class="hljs-number">0</span>
                greenSlider.value = <span class="hljs-number">0</span>
                blueSlider.value = <span class="hljs-number">0</span>
</code></pre>
<p>It's a good idea to reset <code>self.peripheral</code> to nil that way we're not ever trying to write to a phantom device.</p>
<pre><code class="lang-swift">                <span class="hljs-keyword">self</span>.peripheral = <span class="hljs-literal">nil</span>
</code></pre>
<p>Finally, because we've disconnected, start scanning again!</p>
<pre><code class="lang-swift">                <span class="hljs-comment">// Start scanning again</span>
                <span class="hljs-built_in">print</span>(<span class="hljs-string">"Central scanning for"</span>, <span class="hljs-type">ParticlePeripheral</span>.particleLEDServiceUUID);
                centralManager.scanForPeripherals(withServices: [<span class="hljs-type">ParticlePeripheral</span>.particleLEDServiceUUID],
                                                  options: [<span class="hljs-type">CBCentralManagerScanOptionAllowDuplicatesKey</span> : <span class="hljs-literal">true</span>])
            }
</code></pre>
<p>Alright! We just about ready to test. Let's move on to the next (and final) step.</p>
<h2 id="heading-test-the-sliders">Test the sliders.</h2>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/Flow-5-3af7db2e-8bf7-4561-98c2-a1b7ab0c685b.jpg" alt="Next section test!" width="600" height="400" loading="lazy"></p>
<p>The hard work is done. Now it's time to play!</p>
<p>The easiest way to test everything is to <strong>click the Play button</strong> in the top left or the <strong>Command + R</strong> keyboard shortcut. Xcode will load the app to your phone. You should see a white screen proceeded by a screen with your sliders!</p>
<p>The sliders should stay greyed out until connected to your Particle Mesh board. You can check your log output if the connection has been established.</p>
<pre><code>View loaded
Central state update
Central scanning <span class="hljs-keyword">for</span> B4250400-FB4B<span class="hljs-number">-4746</span>-B2B0<span class="hljs-number">-93</span>F0E61122C6
Connected to your Particle Board
LED service found
Red LED characteristic found
Green LED characteristic found
Blue LED characteristic found
</code></pre><p>(Look familiar? We're connected!)</p>
<p>If you followed everything perfectly, you should be able to move the sliders. Better yet, the RGB LED on the Particle Mesh board should change color.</p>
<p><img src="https://www.jaredwolff.com/the-ultimate-how-to-bluetooth-swift-with-hardware-in-20-minutes/images/DSC01556-1fda5018-f1f5-4855-8705-f7d344ce3d78.jpeg" alt="Final test results" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article you've learned how to connect your Particle Mesh board and iOS device over Bluetooth. We've learned how to connect to each of the available characteristics. Plus, on top of it all, make a clean interface to do it all in.</p>
<p>As you can imagine, you can go down the rabbit hole with Bluetooth on iOS. There's more coming in my upcoming guide: <strong>The Ultimate Guide to Particle Mesh.</strong> Subscribers to my list get access to pre-launch content and a discount when it comes out! <a target="_blank" href="https://www.jaredwolff.com/the-ultimate-guide-to-particle-mesh/">Click here to get signed up.</a></p>
<h2 id="heading-code">Code</h2>
<p>The full source code is available on <a target="_blank" href="https://github.com/jaredwolff/swift-bluetooth-particle-rgb">Github.</a> If you find it useful, hit the star button. ⭐️</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 2 Best Ways to Get Particle Mesh Working With Blynk ]]>
                </title>
                <description>
                    <![CDATA[ By Jared Wolff This post is originally from my blog on www.jaredwolff.com. Writing an app takes time. It takes even more time to write one that works with hardware. Luckily there's a solution to this problem. Enter Blynk. It's an app that connects to... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/2-best-ways-to-get-particle-mesh-working-with-blynk/</link>
                <guid isPermaLink="false">66d850435a0b456f4d32147d</guid>
                
                    <category>
                        <![CDATA[ particle ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 29 Jul 2019 13:01:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/07/Copy-of-Mesh-to-Blynk.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jared Wolff</p>
<p><strong>This post is originally from my blog on <a target="_blank" href="https://www.jaredwolff.com/two-best-ways-to-get-particle-mesh-working-with-blynk/">www.jaredwolff.com</a>.</strong></p>
<p>Writing an app takes time. It takes even more time to write one that works with hardware.</p>
<p>Luckily there's a solution to this problem.</p>
<p>Enter <a target="_blank" href="http://blynk.io">Blynk</a>.</p>
<p>It's an app that connects to your hardware. It has a drag and drop interface with pre built widgets. That means you can build an app in seconds. Then upload your device sensors readings within minutes.</p>
<p>Blynk does work with Argon, Boron or ethernet connected Xenon. Unfortunately it doesn't work over a Particle Mesh network. In this article you'll learn some of the workarounds to get your mesh based projects up an running.</p>
<h2 id="heading-from-particle-cloud-to-blynk">From Particle Cloud to Blynk</h2>
<p>Let's start with the most simple use case: getting data from any Particle Device to Blynk.</p>
<p>The Air Quality data from <a target="_blank" href="http://jaredwolff.com/homemade-indoor-air-quality-sensor/">Particle Squared</a> is perfect for this example. So, i'll be using that.</p>
<p>First let's create a new Blynk Project</p>
<p><img src="https://www.jaredwolff.com/two-best-ways-to-get-particle-mesh-working-with-blynk/images/IMG_2233-2a80b63a-b88b-4e58-a50b-5fc02923ae23.png" alt="Create Project in Blynk" width="600" height="400" loading="lazy"></p>
<p>Grab the <strong>Auth Token</strong> we'll need that in a bit. You can <strong>tap the Auth Token</strong> to copy it to your clipboard.</p>
<p>Next, let's add a <strong>SuperChart</strong> for this example.</p>
<p><img src="https://www.jaredwolff.com/two-best-ways-to-get-particle-mesh-working-with-blynk/images/IMG_2231-308d94bf-63f4-40a6-98e3-e49ced05c90a.png" alt="Add a SuperChart" width="600" height="400" loading="lazy"></p>
<p>Configure the SuperChart to use a Virtual Pin. We don't have access to the actual hardware pins on the device. <strong>V0</strong> is a good choice.</p>
<p><img src="https://www.jaredwolff.com/two-best-ways-to-get-particle-mesh-working-with-blynk/images/IMG_2232-e53a0997-453e-47ee-b2d1-27a30dc12dfc.png" alt="Select Virtual Pin 0" width="600" height="400" loading="lazy"></p>
<p>To update values in Blynk, we'll have to connect somehow. The best way is to use an <strong>Integration</strong> in the <strong>Particle Console.</strong></p>
<p>In Particle Console, click the icon below the terminal icon. Then click on <strong>New Integration.</strong></p>
<p><img src="https://www.jaredwolff.com/two-best-ways-to-get-particle-mesh-working-with-blynk/images/Screen_Shot_2019-07-27_at_10-33b85b6e-d685-4c1a-b639-423df7b2dd85.43.37_AM.png" alt="Create new Integration in Particle Console" width="600" height="400" loading="lazy"></p>
<p>Look at the example below to see how I filled everything out.</p>
<p><img src="https://www.jaredwolff.com/two-best-ways-to-get-particle-mesh-working-with-blynk/images/Screen_Shot_2019-07-24_at_3-a5433944-8a2a-4b0d-81b6-faa4c038bd65.27.06_PM.png" alt="Enter all the information into the New Integration Screen" width="600" height="400" loading="lazy"></p>
<p>Particle Squared uses the <strong>Event Name</strong> as <strong>**<code>blob</code>. For other projects this may be different. </strong>Remember:** your event name is the same as from <code>Particle.publish(eventName, data)</code>.</p>
<p>The <strong>URL</strong> is set to use the <code>blink-cloud.com</code> address. According to their API a sample URL looks like:</p>
<p><img src="https://www.jaredwolff.com/two-best-ways-to-get-particle-mesh-working-with-blynk/images/Screen_Shot_2019-07-24_at_4-730022d3-f758-43b3-b4cc-bb3012d22d9e.44.06_PM.png" alt="Blink cloud write pin API call" width="600" height="400" loading="lazy"></p>
<p>I'll also include it here so it's easier to copy</p>
<pre><code>http:<span class="hljs-comment">//blynk-cloud.com/auth_token/update/pin?value=value</span>
</code></pre><p>Replace <code>auth_token</code> with the <strong>Auth Token</strong> we got earlier.</p>
<p>Replace <code>pin</code> with the virtual pin we want to modify. In this case <strong>V0</strong></p>
<p>Replace the <code>value</code> with the value you want to use.</p>
<p>We'll reference one of the values in the Particle Squared <code>blob</code>. It's organized like this:</p>
<pre><code>{
  <span class="hljs-string">"temperature"</span>: <span class="hljs-number">28.60</span>,
  <span class="hljs-string">"humidity"</span>: <span class="hljs-number">45.00</span>,
  <span class="hljs-string">"sgp30_tvoc"</span>: <span class="hljs-number">18</span>,
  <span class="hljs-string">"sgp30_c02"</span>: <span class="hljs-number">400</span>,
  <span class="hljs-string">"bme680_temp"</span>: <span class="hljs-number">27.36</span>,
  <span class="hljs-string">"bme680_pres"</span>: <span class="hljs-number">1012.43</span>,
  <span class="hljs-string">"bme680_hum"</span>: <span class="hljs-number">43.80</span>,
  <span class="hljs-string">"bme680_iaq"</span>: <span class="hljs-number">43.90</span>,
  <span class="hljs-string">"bme680_temp_calc"</span>: <span class="hljs-number">27.30</span>,
  <span class="hljs-string">"bme680_hum_calc"</span>: <span class="hljs-number">43.97</span>
}
</code></pre><p>Particle uses <a target="_blank" href="http://mustache.github.io/mustache.5.html">mustache templates</a>. As you can see in the screenshot above, you can set <code>value</code> to <code>{{{temperature}}}</code>.</p>
<p><strong>Note:</strong> If you're working on your own project, it's important to publish with JSON. As a reference the <code>Particle.publish</code> command looks like:</p>
<pre><code><span class="hljs-comment">// Publish data</span>
Particle.publish(<span class="hljs-string">"blob"</span>, <span class="hljs-attr">String</span>::format(<span class="hljs-string">"{\"temperature\":%.2f,\"humidity\":%.2f}"</span>,si7021_data.temperature, si7021_data.humidity) , PRIVATE, WITH_ACK);
</code></pre><p>Click the <strong>big blue Save button</strong> at the bottom of the screen. Then we can move on to the next step!</p>
<h3 id="heading-testing">Testing</h3>
<p>Since creating our Particle Webhook Integration, it's been publishing data to Blynk. Let's go see if it's working.</p>
<p>First, let's go back to the Blynk app. <strong>Hit the Play Button in the top Right</strong> in Blynk screen.</p>
<p><img src="https://www.jaredwolff.com/two-best-ways-to-get-particle-mesh-working-with-blynk/images/IMG_2234-43cebeaa-2dd4-401c-84e5-b365953f4a66.png" alt="Watch data come into Blynk app" width="600" height="400" loading="lazy"></p>
<p>If your integration has been running for a while, you should see the graph populate with data! In the case you don't see anything, let's check the logs.</p>
<p><strong>Go back to your integration</strong> and <strong>scroll towards the bottom</strong>. We want to see if there are any errors.</p>
<p>Not sure what that looks like? Here's an example of an integration with errors:</p>
<p><img src="https://www.jaredwolff.com/two-best-ways-to-get-particle-mesh-working-with-blynk/images/Screen_Shot_2019-07-24_at_4-47e820b4-1636-406e-8ba1-ff22cf899478.55.36_PM.png" alt="Particle console integration errors" width="600" height="400" loading="lazy"></p>
<p>You can scroll further down to investigate why the error has occurred.</p>
<p><img src="https://www.jaredwolff.com/two-best-ways-to-get-particle-mesh-working-with-blynk/images/Screen_Shot_2019-07-24_at_4-2e5843f3-1960-41a7-90b0-d80432d6ef2d.56.36_PM.png" alt="Investigate Particle Integration failure further" width="600" height="400" loading="lazy"></p>
<p>All the way at the bottom shows the response from the server. Depending on the service, they'll give you information why your API call failed. In my case, I was missing values for two fields.</p>
<h3 id="heading-particle-to-blynk-is-working">Particle to Blynk is working!</h3>
<p>You now have a basic way of publishing to a virtual pin in Blynk. There are drawbacks though. Most importantly, you'll have to create an integration for every signal virtual pin. If you have eight readings, that means eight integrations.</p>
<p>Bummer.</p>
<p>In the next section, you'll learn a different way to configure Blynk. Let's go!</p>
<h2 id="heading-local-mesh-using-blynk-library">Local Mesh Using Blynk Library</h2>
<p><img src="https://www.jaredwolff.com/two-best-ways-to-get-particle-mesh-working-with-blynk/images/Mesh_to_Blynk-0a66867b-a193-4b97-801a-b780c9a481e2.png" alt="Particle Mesh to Blynk" width="600" height="400" loading="lazy"></p>
<p>Unlike the first method, we'll be focusing on changing firmware only.</p>
<p>We’ll use a Argon, Boron or Ethernet Connected Xenon and one regular Xenon. For the rest of this tutorial, we'll call these devices an “edge router”.</p>
<p>The Xenon will run the Particle Squared code. Instead of using <code>Particle.publish</code> we'll be using <code>Mesh.publish</code>. This allows us to publish only to the local mesh network.</p>
<p>Meanwhile the edge router is listening for the message. It collects the values and then uses the Blynk API to publish to the app.</p>
<p>Here are the steps:</p>
<h3 id="heading-setup-our-edge-router">Setup our Edge Router</h3>
<p>Pull up the menu by pressing <strong>Cmd+Shift+P</strong>. Type <strong>Install Library.</strong></p>
<p><img src="https://www.jaredwolff.com/two-best-ways-to-get-particle-mesh-working-with-blynk/images/Screen_Shot_2019-07-28_at_4-f8149823-96fc-460f-b47e-2bcf56b670c2.50.29_PM.png" alt="Install library in Visual Studio Code" width="600" height="400" loading="lazy"></p>
<p>Then enter <strong>blynk.</strong> The library should download if you haven't already.</p>
<p>Once installed you can include the library at the top of your <code>.ino</code> file like so:</p>
<pre><code>#include &lt;blynk.h&gt;
</code></pre><p>In our <code>setup()</code> function let's init the Blynk library:</p>
<pre><code><span class="hljs-comment">// Put initialization like pinMode and begin functions here.</span>
Blynk.begin(auth);
</code></pre><p>In our <code>setup()</code> function, subscribe to the <code>temperature</code> event. The connected Xenon will generate this event.</p>
<pre><code><span class="hljs-comment">// Subscribe to temperature events</span>
Mesh.subscribe(<span class="hljs-string">"temperature"</span>,tempHandler);
</code></pre><p>Define <code>tempHandler</code> like this for now:</p>
<pre><code><span class="hljs-comment">// Temperature event handler for mesh</span>
<span class="hljs-keyword">void</span> tempHandler(<span class="hljs-keyword">const</span> char *event, <span class="hljs-keyword">const</span> char *data){
}
</code></pre><p>In the <code>loop()</code> function make sure we have <code>Blynk.run();</code></p>
<pre><code><span class="hljs-comment">// loop() runs over and over again, as quickly as it can execute.</span>
<span class="hljs-keyword">void</span> loop() {
  <span class="hljs-comment">// The core of your code will likely live here.</span>
  Blynk.run();
}
</code></pre><p>Finally, for <code>tempHandler</code> we can add a debug print to monitor events. I've used something like this:</p>
<pre><code>Serial.printlnf(<span class="hljs-string">"event=%s data=%s"</span>, event, data ? data : <span class="hljs-string">"NULL"</span>);
</code></pre><p>Particle uses this in some of their examples. It's perfect for our purposes as well!</p>
<p><strong>Note:</strong> make sure you have <code>Serial.begin()</code> called in your <code>Setup()</code> function!</p>
<p>So now we have <code>tempHandler</code> to receive data from the Xenon. The edge router can now take that data and upload it to Blynk. Let's use the <code>Blynk.virtualWrite</code> function for this:</p>
<pre><code><span class="hljs-comment">// Write the data</span>
Blynk.virtualWrite(V0, data);
</code></pre><p>This will write the temperature value from a Xenon to the <code>V0</code> pin. If you used something other than V0, be sure to change that value here. (This is the same setup as the previous <em>Particle Cloud to Blynk</em> example)</p>
<p><img src="https://www.jaredwolff.com/two-best-ways-to-get-particle-mesh-working-with-blynk/images/IMG_2232-e53a0997-453e-47ee-b2d1-27a30dc12dfc.png" alt="DataStream V0" width="600" height="400" loading="lazy"></p>
<p>The final code for the edge router should look something like this. Compile a flash it to your device when you're ready!</p>
<pre><code><span class="hljs-comment">/*
 * Project blynk-argon-forwarder
 * Description: Argon Blynk forwarder for Particle Mesh. Forwards data from mesh connected devices to Blynk.
 * Author: Jared Wolff
 * Date: 7/25/2019
 */</span>

#include &lt;blynk.h&gt;

char auth[] = <span class="hljs-string">"&lt;ENTER YOUR AUTH KEY&gt;"</span>;

<span class="hljs-comment">// Temperature event handler for mesh</span>
<span class="hljs-keyword">void</span> tempHandler(<span class="hljs-keyword">const</span> char *event, <span class="hljs-keyword">const</span> char *data){
  Serial.printlnf(<span class="hljs-string">"event=%s data=%s"</span>, event, data ? data : <span class="hljs-string">"NULL"</span>);

  <span class="hljs-comment">// Write the data</span>
  Blynk.virtualWrite(V0, data);
}

<span class="hljs-comment">// setup() runs once, when the device is first turned on.</span>
<span class="hljs-keyword">void</span> setup() {

  <span class="hljs-comment">// Serial for debugging</span>
  Serial.begin();

  <span class="hljs-comment">// Put initialization like pinMode and begin functions here.</span>
  Blynk.begin(auth);

  <span class="hljs-comment">// Subscribe to temperature events</span>
  Mesh.subscribe(<span class="hljs-string">"temperature"</span>,tempHandler);

}

<span class="hljs-comment">// loop() runs over and over again, as quickly as it can execute.</span>
<span class="hljs-keyword">void</span> loop() {
  <span class="hljs-comment">// The core of your code will likely live here.</span>
  Blynk.run();

}
</code></pre><p>Remember to set <code>auth</code> using the <code>AUTH TOKEN</code> in the Blynk app!</p>
<h3 id="heading-setting-up-a-xenon">Setting up a Xenon</h3>
<p><img src="https://www.jaredwolff.com/two-best-ways-to-get-particle-mesh-working-with-blynk/images/Copy_of_Compose-a34be8da-a352-4a76-af8c-8c83e65efe50.png" alt="Xenon!" width="600" height="400" loading="lazy"></p>
<p>Create a new project. This time it will be for the Xenon capturing "temperature data."</p>
<p>Let's add a variable called <code>time_millis</code> to the top of the file. The type is <code>system_tick_t</code>. We'll use it to create a simple delay timer for the temperature readings.</p>
<pre><code><span class="hljs-comment">// Global variable to track time (used for temp sensor readings)</span>
system_tick_t time_millis;
</code></pre><p>For the interval, let's use a preprocessor define</p>
<pre><code>#define INTERVAL_MS <span class="hljs-number">2000</span>
</code></pre><p>Now let's tie those together in the <code>loop()</code> function. We'll use an <code>if</code> statement to compare our current system time with that of the last event plus offset. If you ever need a simple timer, this is one of the best ways to do it!</p>
<pre><code><span class="hljs-comment">// Check if our interval &gt; 2000ms</span>
  <span class="hljs-keyword">if</span>( millis() - time_millis &gt; INTERVAL_MS ) {
  }
</code></pre><p>Once we're inside, make sure you reset <code>timer_millis</code>:</p>
<pre><code>        <span class="hljs-comment">//Set time to the 'current time' in millis</span>
    time_millis = millis();
</code></pre><p>Then, we'll generate the temperature value using the <code>random()</code> function. We'll use the two parameter variant. That way we can set the minimum value and the maximum value:</p>
<pre><code>    <span class="hljs-comment">// Create a random number</span>
    int rand = random(<span class="hljs-number">20</span>,<span class="hljs-number">30</span>);
</code></pre><p>Finally we'll <code>Mesh.publish</code> the value:</p>
<pre><code>    <span class="hljs-comment">// Publish our "temperature" value</span>
    Mesh.publish(<span class="hljs-string">"temperature"</span>,<span class="hljs-attr">String</span>::format(<span class="hljs-string">"%d"</span>,rand));
</code></pre><p>When this example runs, the temperature is broadcast to the mesh network. Then, the edge router receives it and forwards it on to Blynk!</p>
<p>You can flash this firmware whenever you're ready. Here's the full code for the Xenon so you can cross compare:</p>
<pre><code><span class="hljs-comment">/*
 * Project blynk-xenon-rgb
 * Description: Recieve RGB level from connected Edge Router. Sends simiulated temperature values via mesh to the Blynk cloud.
 * Author: Jared Wolff
 * Date: 7/25/2019
 */</span>

<span class="hljs-comment">// How often we update the temperature</span>
#define INTERVAL_MS <span class="hljs-number">2000</span>

<span class="hljs-comment">// Global variable to track time (used for temp sensor readings)</span>
system_tick_t time_millis;
<span class="hljs-comment">// setup() runs once, when the device is first turned on.</span>
<span class="hljs-keyword">void</span> setup() {

  <span class="hljs-comment">// Set time to 0</span>
  time_millis = <span class="hljs-number">0</span>;

}

<span class="hljs-comment">// loop() runs over and over again, as quickly as it can execute.</span>
<span class="hljs-keyword">void</span> loop() {

  <span class="hljs-comment">// Check if our interval &gt; 2000ms</span>
  <span class="hljs-keyword">if</span>( millis() - time_millis &gt; INTERVAL_MS ) {
    <span class="hljs-comment">//Set time to the 'current time' in millis</span>
    time_millis = millis();

    <span class="hljs-comment">// Create a random number</span>
    int rand = random(<span class="hljs-number">20</span>,<span class="hljs-number">30</span>);

    <span class="hljs-comment">// Publish our "temperature" value</span>
    Mesh.publish(<span class="hljs-string">"temperature"</span>,<span class="hljs-attr">String</span>::format(<span class="hljs-string">"%d"</span>,rand));

  }

}
</code></pre><h3 id="heading-give-it-a-test">Give it a test!</h3>
<p>Now that we've programmed both devices let's get them talking to each other.</p>
<p>I've already set up the Argon with a mesh network called <strong>8f-9.</strong> I'll explain how to get the Xenon connected with the CLI. You can also used the Particle App.</p>
<p>First, let's connect the Xenon to USB and get it into Listening Mode. After connect, hold the <strong>Mode button</strong> until <strong>blinking blue.</strong></p>


<p>Then use the CLI to set up the mesh network. First let's get the device ID:</p>
<pre><code>Jareds-MacBook-Pro:nrfjprog.sh jaredwolff$ particle identify
? Which device did you mean?
  <span class="hljs-regexp">/dev/</span>tty.usbmodem146401 - Argon
❯ /dev/tty.usbmodem146101 - Xenon
</code></pre><p>If you have multiple devices connect, make sure you select the right one! If prompted, select a device. Your output should look something like:</p>
<pre><code>Your device id is e00fce682d9285fbf4412345
Your system firmware version is <span class="hljs-number">1.3</span><span class="hljs-number">.0</span>-rc<span class="hljs-number">.1</span>
</code></pre><p>We'll need the <strong>id</strong> for the next step. Now, let's run the <code>particle mesh</code> command.</p>
<pre><code>particle mesh add &lt;xenon id&gt; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">id</span> <span class="hljs-attr">of</span> <span class="hljs-attr">your</span> <span class="hljs-attr">argon</span>, <span class="hljs-attr">boron</span>, <span class="hljs-attr">etc</span>&gt;</span></span>
</code></pre><p>Here's an example below:</p>
<pre><code>particle mesh add e00fce682d9285fbf4412345 hamster_turkey
? Enter the network password [hidden]
▄ Adding the device to the network...
</code></pre><p>At the end of it you'll see:</p>
<pre><code>Done! The device should now connect to the cloud.
</code></pre><p>This process is not perfect. During the <code>Adding the device to the network...</code> stage, I had to remove the Xenon using <code>particle mesh remove</code>. Then re-run the <code>particle mesh add</code> command after resetting the Argon.</p>
<p>Now here comes to finale.</p>
<p>Connect the two devices to serial using <code>particle serial monitor --follow</code></p>
<p>If you have the two devices connected, <code>particle serial monitor</code> will prompt you to select:</p>
<pre><code>Jareds-MacBook-Pro:blynk-xenon-rgb jaredwolff$ particle serial monitor --follow
Polling <span class="hljs-keyword">for</span> available serial device...
? Which device did you mean? <span class="hljs-regexp">/dev/</span>tty.usbmodem146101 - Xenon
Opening serial monitor <span class="hljs-keyword">for</span> com port: <span class="hljs-string">"/dev/tty.usbmodem146101"</span>
Serial monitor opened successfully:
</code></pre><p><strong>Remember:</strong> You have to run <code>particle serial monitor</code> for each device you want to connect to.</p>
<p>If all is working, you'll likely see some output from the edge router!</p>
<pre><code>Serial monitor opened successfully:
event=temperature data=<span class="hljs-number">21</span>
event=temperature data=<span class="hljs-number">28</span>
event=temperature data=<span class="hljs-number">21</span>
event=temperature data=<span class="hljs-number">27</span>
event=temperature data=<span class="hljs-number">28</span>
event=temperature data=<span class="hljs-number">26</span>
event=temperature data=<span class="hljs-number">23</span>
event=temperature data=<span class="hljs-number">26</span>
event=temperature data=<span class="hljs-number">21</span>
</code></pre><p>Looking at the app, the <strong>Super Chart</strong> should be reacting to this new data.</p>
<p>Compare the last value in the command line to the last on the chart? Do they match? If so, you made it to the end of this example!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial you've learned how to forward Particle Cloud data to Blynk. You've also learned how to do the same using a Particle Argon, Boron or ethernet connected Xenon. Awe yea. ??</p>
<p>Now that you have the tools to Blink-ify your Particle Mesh powered projects, it's time to get to work!</p>
<p><strong>Like this post?</strong></p>
<p>This post is an excerpt from my upcoming <em>Ultimate Guide to Particle Mesh</em>. I'll be sharing more exclusive content with my mailing list as it get's closer to launch. <a target="_blank" href="https://jaredwolff.com/the-ultimate-guide-to-particle-mesh/">You can sign up here for updates.</a></p>
<p><strong>Still have questions?</strong></p>
<p>Leave a comment or <a target="_blank" href="https://www.jaredwolff.com/about">shoot me a line.</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Particle's Powerful Bluetooth API ]]>
                </title>
                <description>
                    <![CDATA[ By Jared Wolff This post is originally from www.jaredwolff.com I was defeated. I had spent the whole night trying to get a Bluetooth Low Energy project working. It was painful. It was frustrating. I was ready to give up. That was during the early day... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-particles-powerful-bluetooth-api/</link>
                <guid isPermaLink="false">66d8505ac15439a8d5631e7f</guid>
                
                    <category>
                        <![CDATA[ Bluetooth Low Energy ]]>
                    </category>
                
                    <category>
                        <![CDATA[ hardware ]]>
                    </category>
                
                    <category>
                        <![CDATA[ particle ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 15 Jul 2019 12:39:52 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/07/Particle-Bluetooth.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jared Wolff</p>
<p><strong>This post is originally from <a target="_blank" href="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/">www.jaredwolff.com</a></strong></p>
<p>I was defeated.</p>
<p>I had spent the whole night trying to get a Bluetooth Low Energy project working. It was painful. It was frustrating. I was ready to give up.</p>
<p>That was during the early days of Bluetooth Low Energy. Since then it's gotten easier and easier to develop. The Particle Mesh Bluetooth Library is no exception.</p>
<p>In this walkthrough, i'll show you how to use Particle's Bluetooth API. We'll configure some LEDs and watch them change over all devices in the Mesh network. We'll be using an Argon and Xenon board.</p>
<p>Ready? Let's get started!</p>
<p>P.S. this post is lengthy. If you want something to download, <a target="_blank" href="https://www.jaredwolff.com/files/how-to-use-particles-powerful-bluetooth-api-pdf">click here for a beautifully formatted PDF.</a></p>
<h2 id="heading-stage-1-setting-up-bluetooth">Stage 1: Setting Up Bluetooth</h2>
<ol>
<li><a target="_blank" href="https://www.particle.io/workbench/">Download/Install Particle Workbench</a></li>
<li><p>Create a new Project. I picked a suitable location and then named it <code>ble_mesh</code></p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/Screen_Shot_2019-07-13_at_5-4348ea15-e220-4138-8d28-a8c5de99e9fe.32.11_PM.png" alt="Create a new Project in Particle Workbench" width="730" height="565" loading="lazy"></p>
</li>
<li><p>Go to your <code>/src/</code> direcory and open your <code>&lt;your project name&gt;.ino</code> file</p>
</li>
<li><p>Then make sure you change the version of your deviceOS to  &gt; <strong>1.3.0</strong></p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/Screen_Shot_2019-07-13_at_5-9d20c90b-e27c-4609-9917-2ec1bb849727.40.15_PM.png" alt="Select DeviceOS Version" width="730" height="458" loading="lazy"></p>
</li>
</ol>
<h3 id="heading-write-the-code">Write the Code</h3>
<p>We want to set up a service with 3 characteristics. The characteristics relate to the intensity of the RGB LEDs respectively. Here's how to get your Bluetooth Set Up:</p>
<ol>
<li><p>In your <code>Setup()</code> function enable app control of your LED</p>
<pre><code> RGB.control(<span class="hljs-literal">true</span>);
</code></pre></li>
<li><p>Set up your UUIDs at the top of your <code>.ino</code> file</p>
<p>     const char<em> serviceUuid = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
     const char</em> red         = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
     const char<em> green       = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";
     const char</em> blue        = "6E400004-B5A3-F393-E0A9-E50E24DCCA9E";</p>
<p> UUIDs are unique identifiers or addresses. They're used to differentiate different services and characteristics on a device.</p>
<p> The above UUIDs are used in previous Particle examples. If you want to create your own you can use  <code>uuidgen</code> on the OSX command line. You can also go to a website like <strong><a target="_blank" href="https://www.guidgenerator.com/online-guid-generator.aspx">Online GUID Generator</a>.</strong></p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/Screen_Shot_2019-07-14_at_11-343e1df6-69e8-4560-98b9-f2f54caeb7d3.28.46_AM.png" alt="Online GUID Generator" width="730" height="620" loading="lazy"></p>
<p> Use the above settings to get your own UUID. You can then create your service and characteristic UUIDS from this generated one:</p>
<p>     const char<em> serviceUuid = "b425040<strong>0</strong>-fb4b-4746-b2b0-93f0e61122c6"; //service
     const char</em> red         = "b4250401-fb4b-4746-b2b0-93f0e61122c6"; //red char
     const char<em> green       = "b4250402-fb4b-4746-b2b0-93f0e61122c6"; //green char
     const char</em> blue        = "b4250403-fb4b-4746-b2b0-93f0e61122c6"; //blue char</p>
<p> There's no right or wrong way to do this. But you have to be careful you're not using the UUIDs reserved by the Bluetooth SIG. This is highly unlikely. If you do want to double check you can go <a target="_blank" href="https://www.bluetooth.com/specifications/gatt/characteristics/">here</a> and <a target="_blank" href="https://www.bluetooth.com/specifications/gatt/services/">here</a>.</p>
<p> For now, we'll stick with the first set of UUIDs.</p>
</li>
<li><p>In <code>Setup()</code>, initialize your service.</p>
<p>     // Set the RGB BLE service
     BleUuid rgbService(serviceUuid);</p>
<p> This is the first step of "registering' your service. More on this below.</p>
</li>
<li><p>Initialize each characteristic in <code>Setup()</code></p>
<p>     BleCharacteristic redCharacteristic("red", BleCharacteristicProperty::WRITE_WO_RSP, red, serviceUuid, onDataReceived, (void<em>)red);
     BleCharacteristic greenCharacteristic("green", BleCharacteristicProperty::WRITE_WO_RSP, green, serviceUuid, onDataReceived, (void</em>)green);
     BleCharacteristic blueCharacteristic("blue", BleCharacteristicProperty::WRITE_WO_RSP, blue, serviceUuid, onDataReceived, (void*)blue);</p>
<p> For this setup, we're going to use the <code>WRITE_WO_RSP</code> property. This allows us to write the data and expect no response.
 I've referenced the UUIDs as the next two parameters. The first being the characteristic UUID. The second being the service UUID.</p>
<p> The next parameter is the callback function. When data is written to this callback, this function will fire.</p>
<p> Finally the last parameter is the context. What does this mean exactly? We're using the same callback for all three characteristics. The only way we can know which characteristic was written to (in deviceOS at least) is by setting a context. In this case we're going to use the already available UUIDs.</p>
</li>
<li><p>Right after defining the characteristics, let's add them so they show up:</p>
<p>     // Add the characteristics
     BLE.addCharacteristic(redCharacteristic);
     BLE.addCharacteristic(greenCharacteristic);
     BLE.addCharacteristic(blueCharacteristic);</p>
</li>
<li><p>Set up the callback function.</p>
<p>     // Static function for handling Bluetooth Low Energy callbacks
     static void onDataReceived(const uint8_t<em> data, size_t len, const BlePeerDevice&amp; peer, void</em> context) {</p>
<p>     }</p>
<p> You can do this at the top of the file (above <code>Setup()</code>) We will define this more later.</p>
</li>
<li><p>Finally, in order for your device to be connectable, we have to set up advertising. Place this code at the end of your <code>Setup()</code> function</p>
<p>     // Advertising data
     BleAdvertisingData advData;</p>
<p>     // Add the RGB LED service
     advData.appendServiceUUID(rgbService);</p>
<p>     // Start advertising!
     BLE.advertise(&amp;advData);</p>
<p> First we create a <code>BleAdvertisingData</code> object. We add the <code>rgbService</code> from Step 3. Finally, we can start advertising so our service and characteristics are discoverable!</p>
</li>
</ol>
<h3 id="heading-time-to-test">Time to test</h3>
<p>At this point we have a minimally viable program. Let's compile it and program it to our Particle hardware. This should work with any Mesh enabled device. (Xenon, Argon, Boron)</p>
<ol>
<li>Before we start testing, temporarily add <code>SYSTEM_MODE(MANUAL);</code> to the top of your file. This will prevent the device connecting to the mesh network. If the device is blinking blue on startup, you'll have to set it up with the <a target="_blank" href="https://apps.apple.com/ru/app/particle-iot/id991459054?l=en">Particle App</a> before continuing.</li>
<li><p><a target="_blank" href="https://github.com/particle-iot/device-os/releases/tag/v1.3.0-rc.1">Download the 1.3.0-rc.1 image here.</a> For Xenon, you'll need <strong>xenon-system-part1@1.3.0-rc.1.bin.</strong> For others look for <strong>boron-system-part1@1.3.0-rc.1.bin</strong> and <strong>argon-system-part1@1.3.0-rc.1.bin.</strong> The files are at the bottom of the page under <strong>Assets</strong></p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/Screen_Shot_2019-07-14_at_11-df9b46f4-e230-484e-b69e-828526f5566e.39.39_AM.png" alt="Assets location on DeviceOS Release Page" width="730" height="498" loading="lazy"></p>
</li>
<li><p>Put your device into DFU mode. Hold the <strong>Mode Button</strong> and momentarily click the <strong>Reset</strong> <strong>Button.</strong> Continue holding the <strong>Mode Button</strong> until the LED blinks yellow.</p>
</li>
<li>In a command line window, change directories to where you stored the file you downloaded. In my case the command is <code>cd ~/Downloads/</code></li>
<li><p>Then run:</p>
<p>     particle flash --usb xenon-system-part1@1.3.0-rc.1.bin</p>
<p> This will install the latest OS to your Xenon. Once it's done it will continue to rapidly blink yellow. Again if you have a different Particle Mesh device, change the filename to match.</p>
</li>
<li><p>In Visual Code, use the <strong>Command + Shift + P</strong> key combination to pop up the command menu. Select <strong>Particle: Compile application (local)</strong></p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/Screen_Shot_2019-07-13_at_10-8cb8dda2-73ae-4b0d-af5b-33892d66752e.52.19_PM.png" alt="Compile application (local) choice" width="730" height="552" loading="lazy"></p>
</li>
<li><p>Fix any errors that may pop up.</p>
</li>
<li><p>Then, open the same menu and select <strong>Flash application (local)</strong></p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/Screen_Shot_2019-07-13_at_10-4ff7bc95-58f1-497f-9edf-9eadb69e3abb.51.59_PM.png" alt="Flash application (local) choice" width="730" height="552" loading="lazy"></p>
</li>
<li><p>When programming is complete, pull out your phone.  Then, open your favorite Bluetooth Low Energy app. The best ones are <strong><a target="_blank" href="https://apps.apple.com/cn/app/nrf-connect/id1054362403?l=en">NRF Connect</a></strong> and <strong><a target="_blank" href="https://apps.apple.com/ru/app/lightblue-explorer/id557428110?l=en">Light Blue Explorer.</a></strong> I'm going to use Light Blue Explorer for this example.</p>
</li>
<li><p>Check if a device named <strong>"Xenon-"</strong> is advertising. Insert <strong></strong> with the unique ID for your device.</p>
<p><img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/IMG_2187-aa8b88cc-f423-4b5a-8bb0-e1f75c3b7dd9.png" alt="Light Blue Explorer Scan Results" width="400" height="711" loading="lazy"></p>
</li>
<li><p>Find your device and click the name.</p>
</li>
<li><p>Look at the list of services &amp; characteristics. Does it include the service and characteristic UUID's that we have set so far? For instance, does the service UUID show up as <strong>6E400001-B5A3-F393-E0A9-E50E24DCCA9E</strong>?</p>
<p><img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/IMG_2188-d7759af0-964e-4067-9ca2-d78edd190410.png" alt="Confirm Light Blue Explorer has new characteristic UUIDs" width="400" height="711" loading="lazy"></p>
<p>If everything shows up as you expect, you're in a good place. If not go through the earlier instructions to make sure everything matches.</p>
</li>
</ol>
<h2 id="heading-stage-2-handling-data">Stage 2: Handling Data</h2>
<p>The next stage of our project is to process write events. We'll be updating our <code>onDataReceived</code> function.</p>
<h3 id="heading-write-the-code-1">Write the Code</h3>
<ol>
<li><p>First, let's create a struct that will keep the state of the LEDs. This can be done at the top of the file.</p>
<p>     // Variables for keeping state
     typedef struct {
       uint8_t red;
       uint8_t green;
       uint8_t blue;
     } led_level_t;</p>
</li>
<li><p>The second half of that is to create a static variable using this data type</p>
<p>     // Static level tracking
     static led_level_t m_led_level;</p>
<p> The first two steps allows us to use one single variable to represent the three values of the RGB LED.</p>
</li>
<li><p>Next, let's check for basic errors inside the <code>onDataReceive</code> function For instance we want to make sure that we're receiving only one byte.</p>
<p>     // We're only looking for one byte
       if( len != 1 ) {
         return;
         }</p>
</li>
<li><p>Next, we want to see which characteristic this event came from. We can use the <code>context</code> variable to determine this.</p>
<p>     // Sets the global level
       if( context == red ) {
         m_led_level.red = data[0];
       } else if ( context == green ) {
         m_led_level.green = data[0];
       } else if ( context == blue ) {
         m_led_level.blue = data[0];
       }</p>
<p> Remember, in this case context will be equal to the pointer of either the red, green, or blue UUID string. You can also notice we're setting <code>m_led_level</code>. That way we can update the RGB led even if only one value has changed.</p>
</li>
<li><p>Finally, once set, you can write to the <code>RGB</code> object</p>
<p>     // Set RGB color
         RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);</p>
</li>
</ol>
<h3 id="heading-test-the-code">Test the Code</h3>
<p>Let's go through the same procedure as before to flash the device.</p>
<ol>
<li>Put your device into DFU mode. Hold the <strong>Mode Button</strong> and click the <strong>Reset</strong> <strong>Button.</strong> Continue holding the <strong>Mode Button</strong> until the LED blinks yellow.</li>
<li><p>Then, open the same menu and select <strong>Flash application (local)</strong></p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/Screen_Shot_2019-07-13_at_10-4ff7bc95-58f1-497f-9edf-9eadb69e3abb.51.59_PM.png" alt="Flash application (local) choice" width="730" height="552" loading="lazy"></p>
</li>
<li><p>Once it's done programming, connect to the device using <strong>Light Blue Explorer</strong>.</p>
</li>
<li>Tap on the characteristic that applies to the red LED.</li>
<li><p><strong>Write FF</strong>. The red LED should turn on.</p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/IMG_2191-b8ad0693-f4f8-4828-ae99-b0a0e204cc50.jpg" alt="Write new value choice" width="400" height="711" loading="lazy"></p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/IMG_2190-2c799875-22e5-44bc-9edc-c647cf8669f6.png" alt="Write the hex value of 0xff" width="400" height="711" loading="lazy"></p>
</li>
<li><p><strong>Write 00</strong>. The red LED should turn off.</p>
</li>
<li>Do the same for the other two characteristics. We now have full control of the RGB LED over Bluetooth Low Energy!</li>
</ol>
<h2 id="heading-stage-3-sharing-via-mesh">Stage 3: Sharing Via Mesh</h2>
<p>Finally, now that we're successfully receiving BLE message, it's time to forward them on to our mesh network.</p>
<h3 id="heading-write-the-code-2">Write the Code</h3>
<ol>
<li>First let's remove MANUAL mode. Comment out <code>SYSTEM_MODE(MANUAL);</code></li>
<li><p>At the top of the file let's add a variable we'll used to track if we need to publish</p>
<p>     // Tracks when to publish to Mesh
     static bool m_publish;</p>
</li>
<li><p>Then initialize it in <code>Setup()</code></p>
<p>     // Set to false at first
     m_publish = false;</p>
</li>
<li><p>Then, after setting the RGB led in the <code>onDataReceived</code> callback, let's set it true:</p>
<p>     // Set RGB color
     RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);</p>
<p>     // Set to publish
     m_publish = true;</p>
</li>
<li><p>Let's add a conditional in the <code>loop()</code> function. This will cause us to publish the LED status to the Mesh network:</p>
<p>     if( m_publish ) {
         // Reset flag
         m_publish = false;</p>
<p>         // Publish to Mesh
       Mesh.publish("red", String::format("%d", m_led_level.red));
       Mesh.publish("green", String::format("%d", m_led_level.green));
       Mesh.publish("blue", String::format("%d", m_led_level.blue));
     }</p>
<p> <code>Mesh.publish</code> requires a string for both inputs. Thus, we're using <code>String::format</code> to create a string with our red, green and blue values.</p>
</li>
<li><p>Then let's subscribe to the same variables in <code>Setup()</code>. That way another device can cause the LED on this device to update as well.</p>
<p>     Mesh.subscribe("red", meshHandler);
     Mesh.subscribe("green", meshHandler);
     Mesh.subscribe("blue", meshHandler);</p>
</li>
<li><p>Toward the top of the file we want to create <code>meshHandler</code></p>
<p>     // Mesh event handler
     static void meshHandler(const char <em>event, const char </em>data)
     {
     }</p>
</li>
<li><p>In this application, we need the <code>event</code> parameter and <code>data</code> parameter. In order use them, we have to change them to a <code>String</code> type. That way we can use the built in conversion and comparison functions. So, inside the <code>meshHandler</code> function add:</p>
<p>       // Convert to String for useful conversion and comparison functions
       String eventString = String(event);
       String dataString = String(data);</p>
</li>
<li><p>Finally we do some comparisons. We first check if the event name matches. Then we set the value of the <code>dataString</code> to the corresponding led level.</p>
<p>       // Determine which event we recieved
       if( eventString.equals("red") ) {
         m_led_level.red = dataString.toInt();
       } else if ( eventString.equals("green") ) {
         m_led_level.green = dataString.toInt();
       } else if ( eventString.equals("blue") ) {
         m_led_level.blue = dataString.toInt();
       } else {
             return;
         }</p>
<p>       // Set RGB color
       RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);</p>
<p> Then at the end we set the new RGB color. Notice how I handle an unknown state by adding a <code>return</code> statement in the <code>else</code> section. It's always good to filter out error conditions before they wreak havoc!</p>
</li>
</ol>
<h3 id="heading-test-the-code-1">Test the Code</h3>
<ol>
<li>Open the Particle App on your phone</li>
<li><p>Let's set up the Argon first. <strong>If it's not blinking blue, hold the mode button until it's blinking blue.</strong></p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/IMG_1216-f78725ab-a9f5-4270-b389-73d6dddb1f62.jpg" alt="Particle Argon with Blue LED" width="730" height="548" loading="lazy"></p>
<p> Note: if you've already programmed the app, the LED will be off by default. <strong>Hold the mode button for 5 seconds and then continue.</strong></p>
</li>
<li><p>Go through the pairing process. The app walks you though all the steps. <strong>Make sure you remember the Admin password for your mesh network.</strong></p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/IMG_2194-2482aa12-082c-4786-8883-860b50b4cd53.png" alt="Particle Setup App Board Choice" width="400" height="711" loading="lazy"></p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/IMG_2195-2d030603-e59f-4e76-9d1a-9d4f2c078a4e.png" alt="Scan the sticker" width="400" height="711" loading="lazy"></p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/IMG_2198-80bb83d8-818b-4cd8-a583-9262da9b5121.png" alt="Pairing with your Argon" width="400" height="711" loading="lazy"></p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/IMG_2199-e3c107dd-2704-4aa3-9781-550ad14ea7fc.png" alt="Enter wifi password" width="400" height="711" loading="lazy"></p>
</li>
<li><p>Program an Argon with the latest firmware (1.3.0) (see <strong>Stage 1 - Time to Test - Step 2</strong> for a reminder on how to do this)</p>
</li>
<li>Once rapidly blinking yellow, program the Argon with the Tinker app. You can download it at the <a target="_blank" href="https://github.com/particle-iot/device-os/releases/tag/v1.3.0-rc.1">release page</a>.</li>
<li><p>Once we have a nice solid Cyan LED (connected to the Particle Cloud) we'll program the app. Use the <strong>Cloud Flash</strong> option in the drop down menu.</p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/Screen_Shot_2019-07-15_at_9-a50458b1-ade1-4d4d-818b-ef214f3fec5d.55.19_AM.png" alt="Cloud Flash option" width="730" height="527" loading="lazy"></p>
<p> As far as I can tell, Particle forces any device flashed locally into safe mode when connecting to the cloud. It may be my setup. Your mileage may vary here. Best to use  <strong>Cloud Flash</strong>.</p>
<p> Make sure you select the correct deviceOS version (<strong>1.3.0-rc1</strong>), device type (<strong>Argon</strong>) and device name (<strong>What you named it during setup</strong>)</p>
</li>
<li><p>Connect to the Xenon using the <strong>phone app</strong></p>
</li>
<li>Connect the Xenon to your Mesh network using the phone app</li>
<li><p>Flash your Xenon using <strong>Cloud Flash</strong>. Use the name that you gave it during the phone app setup. As long as the device is connected to Particle Cloud or in safe mode (Purple LED), it should program.</p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/Screen_Shot_2019-07-15_at_10-2f76843b-3cee-4818-adfb-7ece4173df2d.06.32_AM.png" alt="Confirm board type, deviceOS version and device name" width="730" height="527" loading="lazy"></p>
<p> <img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/Screen_Shot_2019-07-15_at_10-8e140009-440c-480d-838e-b83c782a8c96.08.47_AM.png" alt="Cloud flash option" width="730" height="527" loading="lazy"></p>
</li>
<li><p>Once connected, let's get to the fun part. Open up <strong>Light Blue Explorer.</strong> Connect to either the <strong>Argon</strong> or the <strong>Xenon</strong>.</p>
<p><img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/IMG_2200-e1c513ba-6689-4652-b442-e5c6f916d619.png" alt="Select either the Argon or Xenon" width="400" height="711" loading="lazy"></p>
</li>
<li><p>Select one of the LED characteristics and change the value.</p>
<p><img src="https://www.jaredwolff.com/how-to-use-particles-powerful-bluetooth-api/images/IMG_0627-2db8ab26-99e1-46a2-9583-97126fbe2594.jpg" alt="Argon and Xenon with red LEDs on" width="730" height="973" loading="lazy"></p>
<p>The LED should change on all devices!</p>
</li>
</ol>
<h2 id="heading-final-code">Final Code</h2>
<p>Here's the final code with all the pieces put together. You can use this to make sure you put them in the right place!!</p>
<p>    /*</p>
<ul>
<li>Project ble_mesh</li>
<li>Description: Bluetooth Low Energy + Mesh Example</li>
<li>Author: Jared Wolff</li>
<li><p>Date: 7/13/2019
*/</p>
<p>//SYSTEM_MODE(MANUAL);</p>
<p>// UUIDs for service + characteristics
const char<em> serviceUuid = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
const char</em> red         = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
const char<em> green       = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";
const char</em> blue        = "6E400004-B5A3-F393-E0A9-E50E24DCCA9E";</p>
<p>// Set the RGB BLE service
BleUuid rgbService(serviceUuid);</p>
<p>// Variables for keeping state
typedef struct {
uint8_t red;
uint8_t green;
uint8_t blue;
} led_level_t;</p>
<p>// Static level tracking
static led_level_t m_led_level;</p>
<p>// Tracks when to publish to Mesh
static bool m_publish;</p>
<p>// Mesh event handler
static void meshHandler(const char <em>event, const char </em>data)
{</p>
<p>// Convert to String for useful conversion and comparison functions
String eventString = String(event);
String dataString = String(data);</p>
<p>// Determine which event we recieved
if( eventString.equals("red") ) {
 m_led_level.red = dataString.toInt();
} else if ( eventString.equals("green") ) {
 m_led_level.green = dataString.toInt();
} else if ( eventString.equals("blue") ) {
 m_led_level.blue = dataString.toInt();
} else {
     return;
 }</p>
<p>// Set RGB color
RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);</p>
<p>}</p>
<p>// Static function for handling Bluetooth Low Energy callbacks
static void onDataReceived(const uint8_t<em> data, size_t len, const BlePeerDevice&amp; peer, void</em> context) {</p>
<p>// We're only looking for one byte
if( len != 1 ) {
 return;
}</p>
<p>// Sets the global level
if( context == red ) {
 m_led_level.red = data[0];
} else if ( context == green ) {
 m_led_level.green = data[0];
} else if ( context == blue ) {
 m_led_level.blue = data[0];
}</p>
<p>// Set RGB color
RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);</p>
<p>// Set to publish
m_publish = true;</p>
<p>}</p>
<p>// setup() runs once, when the device is first turned on.
void setup() {</p>
<p>// Enable app control of LED
RGB.control(true);</p>
<p>// Init default level
m_led_level.red = 0;
m_led_level.green = 0;
m_led_level.blue = 0;</p>
<p>// Set to false at first
m_publish = false;</p>
<p>// Set the subscription for Mesh updates
Mesh.subscribe("red",meshHandler);
Mesh.subscribe("green",meshHandler);
Mesh.subscribe("blue",meshHandler);</p>
<p>// Set up characteristics
BleCharacteristic redCharacteristic("red", BleCharacteristicProperty::WRITE_WO_RSP, red, serviceUuid, onDataReceived, (void<em>)red);
BleCharacteristic greenCharacteristic("green", BleCharacteristicProperty::WRITE_WO_RSP, green, serviceUuid, onDataReceived, (void</em>)green);
BleCharacteristic blueCharacteristic("blue", BleCharacteristicProperty::WRITE_WO_RSP, blue, serviceUuid, onDataReceived, (void*)blue);</p>
<p>// Add the characteristics
BLE.addCharacteristic(redCharacteristic);
BLE.addCharacteristic(greenCharacteristic);
BLE.addCharacteristic(blueCharacteristic);</p>
<p>// Advertising data
BleAdvertisingData advData;</p>
<p>// Add the RGB LED service
advData.appendServiceUUID(rgbService);</p>
<p>// Start advertising!
BLE.advertise(&amp;advData);
}</p>
<p>// loop() runs over and over again, as quickly as it can execute.
void loop() {</p>
<p>// Checks the publish flag,
// Publishes to a variable called "red" "green" and "blue"
if( m_publish ) {</p>
<p> // Reset flag
 m_publish = false;</p>
<p> // Publish to Mesh
 Mesh.publish("red", String::format("%d", m_led_level.red));
 Mesh.publish("green", String::format("%d", m_led_level.green));
 Mesh.publish("blue", String::format("%d", m_led_level.blue));
}</p>
<p>}</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial you learned how to add Bluetooth to a Particle Mesh project. As you can imagine, the possibilities are endless. For instance you can add user/administrative apps into the experience. <em>Now that's awesome.</em> ?</p>
<p>You can expect more content like this in my upcoming book: <strong><em>The Ultimate Guide to Particle Mesh</em></strong>. Subscribe to my list for updates and insider content. Plus all early subscribers get a discount when it's released! <a target="_blank" href="https://www.jaredwolff.com/the-ultimate-guide-to-particle-mesh">Click here to sign up.</a></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
