This commit is contained in:
jwcooper 2021-03-04 15:43:33 +00:00
parent 0904d6b86f
commit e2601311f1
7 changed files with 1686 additions and 1648 deletions

0
.nojekyll Normal file
View file

View file

@ -53,7 +53,7 @@
.highlight .cs {
color: #75715e;
}
.highlight .c, .highlight .cd {
.highlight .c, .highlight .ch, .highlight .cd, .highlight .cpf {
color: #75715e;
}
.highlight .err {
@ -137,7 +137,7 @@
.highlight .s1 {
color: #e6db74;
}
.highlight .s {
.highlight .s, .highlight .sa, .highlight .dl {
color: #e6db74;
}
.highlight .na {
@ -152,41 +152,52 @@
.highlight .ne {
color: #a6e22e;
}
.highlight .nf {
.highlight .nf, .highlight .fm {
color: #a6e22e;
}
.highlight .vc {
color: #ffffff;
background-color: #272822;
}
.highlight .nn {
color: #ffffff;
background-color: #272822;
}
.highlight .nl {
color: #ffffff;
background-color: #272822;
}
.highlight .ni {
color: #ffffff;
background-color: #272822;
}
.highlight .bp {
color: #ffffff;
background-color: #272822;
}
.highlight .vg {
color: #ffffff;
background-color: #272822;
}
.highlight .vi {
color: #ffffff;
background-color: #272822;
}
.highlight .nv {
.highlight .nv, .highlight .vm {
color: #ffffff;
background-color: #272822;
}
.highlight .w {
color: #ffffff;
background-color: #272822;
}
.highlight {
color: #ffffff;
background-color: #272822;
}
.highlight .n, .highlight .py, .highlight .nx {
color: #ffffff;
background-color: #272822;
}
.highlight .ow {
color: #f92672;
@ -216,11 +227,11 @@
<a href="#" id="nav-button">
<span>
NAV
<img src="images/navbar.png" alt="Navbar" />
<img src="images/navbar.png" alt="" />
</span>
</a>
<div class="toc-wrapper">
<img src="images/logo.png" class="logo" alt="Logo" />
<img src="images/logo.png" class="logo" alt="" />
<div class="lang-selector">
<a href="#" data-language-name="shell">CURL</a>
@ -366,17 +377,17 @@
<p>Flat colored .png images are particularly well suited to small image sizes. The image below is 1024 x 768 pixels and was run through the <a href="https://imageoptim.com/versions">ImageOptim</a> tool. The base size on disk is 10665 bytes and the Base64 encoded size is 14221 bytes.</p>
<p><img src="images/cookbook/plain-text-on-a-plain-background.png" alt="Plain text on a plain background" /></p>
<p><img src="images/cookbook/plain-text-on-a-plain-background.png" alt="" /></p>
<p>By optimizing heavily with imagemagick, I was able to get an image under 1024 bytes. The gif below is 703 bytes on disk and 941 bytes when converted to Base64, so it will work even on feeds with history turned on.</p>
<pre class="highlight sh tab-shell"><code><span class="c"># on macOS 10.14 with ImageMagick 6.9.9-37</span>
<span class="gp">$ </span>convert small-image-with-text.gif -colors 3 <span class="se">\</span>
-strip -coalesce -layers Optimize <span class="se">\</span>
<div class="highlight"><pre class="highlight sh tab-shell"><code><span class="c"># on macOS 10.14 with ImageMagick 6.9.9-37</span>
<span class="nv">$ </span>convert small-image-with-text.gif <span class="nt">-colors</span> 3 <span class="se">\</span>
<span class="nt">-strip</span> <span class="nt">-coalesce</span> <span class="nt">-layers</span> Optimize <span class="se">\</span>
small-image-with-text-optim.gif
<span class="gp">$ </span>base64 -i small-image-with-text-optim.gif <span class="se">\</span>
-o small-image-with-text-optim.gif.base64
</code></pre>
<p><img src="images/cookbook/small-image-with-text-optim.gif" alt="Small image with text optim" /></p>
<span class="nv">$ </span><span class="nb">base64</span> <span class="nt">-i</span> small-image-with-text-optim.gif <span class="se">\</span>
<span class="nt">-o</span> small-image-with-text-optim.gif.base64
</code></pre></div>
<p><img src="images/cookbook/small-image-with-text-optim.gif" alt="" /></p>
<h2 id='publishing-image-data'>Publishing Image Data</h2>
<p><a href="https://gist.github.com/abachman/b0d3687227da7f82818174a89b325588">Here&#39;s an example Python sketch</a> that publishes image data to an Adafruit IO feed when a signal is received on another IO feed.</p>
@ -385,7 +396,7 @@
<p>The key chunk of code is here:</p>
<div class="center-column"></div>
<pre class="highlight plaintext"><code># create an in-memory file to store raw image data
<div class="highlight"><pre class="highlight plaintext"><code># create an in-memory file to store raw image data
stream = io.BytesIO()
# write camera data to the stream (file)
@ -406,26 +417,26 @@ if len(value) &gt; 102400:
return
client.publish('image-stream', value)
</code></pre>
</code></pre></div>
<p>We create an image, optimize it, convert it to a Base64 string, and then immediately publish that string to Adafruit IO. It&#39;s also worth noting that we never save the image file to disk, it is only ever present in memory, which saves a bit of wear-and-tear on our Raspberry Pi microSD card.</p>
<p>If you wanted to do the same from a single command line command, given an existing image file, you could use curl&#39;s support for uploading files from stdin:</p>
<div class="center-column"></div>
<pre class="highlight plaintext"><code>$ base64 image.jpg | curl -F value=@- -H "X-AIO-Key: {io_key}" \
<div class="highlight"><pre class="highlight plaintext"><code>$ base64 image.jpg | curl -F value=@- -H "X-AIO-Key: {io_key}" \
https://io.adafruit.com/api/v2/{username}/feeds/{feed_key}/data
</code></pre>
</code></pre></div>
<p>The <code>-F value=@-</code> tells curl, &quot;I want to POST a multipart form with a single parameter named &#39;value&#39; whose value is the input to this command.&quot; The preceding <code>base64</code> command and the <code>|</code> character mean that the input to the curl command is the base64 string version of the binary image data.</p>
<p>Stop by the forums if this leaves you with questions or if you&#39;re looking for examples in your favorite programming language :D</p>
<h1 id='sending-and-storing-json'>Sending and Storing JSON</h1><pre class="highlight javascript tab-javascript"><code><span class="c1">// A basic data record</span>
<h1 id='sending-and-storing-json'>Sending and Storing JSON</h1><div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="c1">// A basic data record</span>
<span class="p">{</span>
<span class="s2">"value"</span><span class="p">:</span> <span class="mf">22.587</span><span class="p">,</span>
<span class="s2">"lat"</span><span class="p">:</span> <span class="mf">38.1123</span><span class="p">,</span>
<span class="s2">"lon"</span><span class="p">:</span> <span class="o">-</span><span class="mf">91.2325</span><span class="p">,</span>
<span class="s2">"ele"</span><span class="p">:</span> <span class="mi">112</span>
<span class="dl">"</span><span class="s2">value</span><span class="dl">"</span><span class="p">:</span> <span class="mf">22.587</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">lat</span><span class="dl">"</span><span class="p">:</span> <span class="mf">38.1123</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">lon</span><span class="dl">"</span><span class="p">:</span> <span class="o">-</span><span class="mf">91.2325</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">ele</span><span class="dl">"</span><span class="p">:</span> <span class="mi">112</span>
<span class="p">}</span>
</code></pre>
</code></pre></div>
<p>Because Adafruit IO supports additional features beyond a basic MQTT brokering service, such as location tagging for data points, the service supports data in the JSON format described in the <a href="/#create-data">HTTP create data API description</a>.</p>
<p>This lets us store the individual value, <code>22.587</code>, and data about the value: its latitude, longitude, and elevation. Data about the data is &quot;metadata&quot;!</p>
@ -435,30 +446,30 @@ client.publish('image-stream', value)
<p><strong>The safest way to can send JSON data as a value</strong> is to &quot;double encode&quot; it before sending, in which case IO will treat it as a raw string. If you&#39;re using something like javascript&#39;s <code>JSON.stringify</code> function or Ruby&#39;s <code>JSON.generate</code>, double encoding means passing the result of <code>JSON.stringify</code> through <code>JSON.stringify</code> a second time.</p>
<div class="center-column"></div>
<pre class="highlight javascript tab-javascript"><code><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span>
<span class="s2">"value"</span><span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span><span class="s2">"sensor-1"</span><span class="p">:</span><span class="mf">22.587</span><span class="p">,</span><span class="s2">"sensor-2"</span><span class="p">:</span><span class="mf">13.182</span><span class="p">})</span>
<div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span>
<span class="dl">"</span><span class="s2">value</span><span class="dl">"</span><span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span><span class="dl">"</span><span class="s2">sensor-1</span><span class="dl">"</span><span class="p">:</span><span class="mf">22.587</span><span class="p">,</span><span class="dl">"</span><span class="s2">sensor-2</span><span class="dl">"</span><span class="p">:</span><span class="mf">13.182</span><span class="p">})</span>
<span class="p">})</span>
</code></pre>
</code></pre></div>
<p>The double encoded JSON string can be sent directly through Adafruit IO without interference from our processing system, because the processing system will not interpret it as JSON. In your receiving code, because the value passed through includes surrounding double quotes, you have to call your parse function twice to restore the JSON object.</p>
<div class="center-column"></div>
<pre class="highlight javascript tab-javascript"><code><span class="kd">var</span> <span class="nx">data</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="kd">var</span> <span class="nx">data</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="kd">var</span> <span class="nx">value</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">value</span><span class="p">)</span>
</code></pre><h2 id='io-formatted-json'>IO formatted JSON</h2><pre class="highlight javascript tab-javascript"><code><span class="p">{</span>
<span class="s2">"value"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"sensor-1"</span><span class="p">:</span><span class="mf">22.587</span><span class="p">,</span><span class="s2">"sensor-2"</span><span class="p">:</span><span class="mf">13.182</span><span class="p">},</span>
<span class="s2">"lat"</span><span class="p">:</span> <span class="mf">38.1123</span><span class="p">,</span>
<span class="s2">"lon"</span><span class="p">:</span> <span class="o">-</span><span class="mf">91.2325</span><span class="p">,</span>
<span class="s2">"ele"</span><span class="p">:</span> <span class="mi">112</span>
</code></pre></div><h2 id='io-formatted-json'>IO formatted JSON</h2><div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="p">{</span>
<span class="dl">"</span><span class="s2">value</span><span class="dl">"</span><span class="p">:</span> <span class="p">{</span><span class="dl">"</span><span class="s2">sensor-1</span><span class="dl">"</span><span class="p">:</span><span class="mf">22.587</span><span class="p">,</span><span class="dl">"</span><span class="s2">sensor-2</span><span class="dl">"</span><span class="p">:</span><span class="mf">13.182</span><span class="p">},</span>
<span class="dl">"</span><span class="s2">lat</span><span class="dl">"</span><span class="p">:</span> <span class="mf">38.1123</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">lon</span><span class="dl">"</span><span class="p">:</span> <span class="o">-</span><span class="mf">91.2325</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">ele</span><span class="dl">"</span><span class="p">:</span> <span class="mi">112</span>
<span class="p">}</span>
</code></pre>
</code></pre></div>
<p>The simplest way to send JSON data to Adafruit IO is include it directly in the datum formatted record you send to IO. For example, if instead of 22.587, I wanted to send something like, {&quot;sensor-1&quot;:22.587,&quot;sensor-2&quot;:13.182}, the &quot;wrapped&quot; version would look like the value on the right.</p>
<p>It&#39;s worth noting that because Adafruit IO parses the entire JSON object that you send it, any valid JSON will be parsed and when it is stored in our system and forwarded to any subscribers, it will be regenerated. The significance of that is that if you publish JSON data with whitespace, it will be stored and republished without whitespace, because our generator produces the most compact JSON format possible.</p>
<h2 id='non-io-formatted-json'>Non-IO formatted JSON</h2><pre class="highlight plaintext"><code>curl -H "Content-Type: application/json" \
<h2 id='non-io-formatted-json'>Non-IO formatted JSON</h2><div class="highlight"><pre class="highlight plaintext"><code>curl -H "Content-Type: application/json" \
-H "X-AIO-Key: toomanysecrets" \
--data '{"sensor-1":22.587,"sensor-2":13.182}' \
https://io.adafruit.com/api/v2/username/feeds/feed-key/data
</code></pre>
</code></pre></div>
<p>Another way you can send raw JSON data is to just send it. If Adafruit IO doesn&#39;t find a &quot;value&quot; key in the JSON object you send, it will treat the whole blob as plain text and store and forward the data. That means with our example JSON object, sending the string <code>{&quot;sensor-1&quot;:22.587,&quot;sensor-2&quot;:13.182}</code> will result in <code>{&quot;sensor-1&quot;:22.587,&quot;sensor-2&quot;:13.182}</code> being stored in IO and sent to MQTT subscribers.</p>
<p><strong>NOTE:</strong> This solution is the riskiest, because if your JSON blob includes the key named <code>value</code>, then IO will interpret <em>that</em> as the value you want to store and ignore all the other keys.</p>
@ -466,11 +477,11 @@ client.publish('image-stream', value)
<p>If you want to be absolutely sure that Adafruit IO will not interfere with the data you&#39;re sending, encode it as a <a href="https://en.wikipedia.org/wiki/Base64">Base64</a> string first.</p>
<div class="center-column"></div>
<pre class="highlight javascript tab-javascript"><code><span class="nx">btoa</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span> <span class="s2">"something"</span><span class="p">:</span> <span class="s2">"here"</span> <span class="p">}))</span>
<div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="nx">btoa</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span> <span class="dl">"</span><span class="s2">something</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">here</span><span class="dl">"</span> <span class="p">}))</span>
<span class="c1">// "eyJzb21ldGhpbmciOiJoZXJlIn0="</span>
<span class="nx">atob</span><span class="p">(</span><span class="s2">"eyJzb21ldGhpbmciOiJoZXJlIn0="</span><span class="p">)</span>
<span class="nx">atob</span><span class="p">(</span><span class="dl">"</span><span class="s2">eyJzb21ldGhpbmciOiJoZXJlIn0=</span><span class="dl">"</span><span class="p">)</span>
<span class="c1">// {"something":"here"}</span>
</code></pre>
</code></pre></div>
<p>This solution is also ideal if you want to store or send binary data with Adafruit IO. You won&#39;t get to see any pretty charts, but your data will remain exactly the way you left it.</p>
<h1 id='webhook-receivers'>Webhook Receivers</h1>
<p>Webhook receiver URLs give you a limited use, unique API address that you can send data to and have it appear in your Adafruit IO feed. Webhook URLs can be shared with anyone and used from anywhere on the web.</p>

3053
index.html

File diff suppressed because it is too large Load diff

167
mqtt.html
View file

@ -53,7 +53,7 @@
.highlight .cs {
color: #75715e;
}
.highlight .c, .highlight .cd {
.highlight .c, .highlight .ch, .highlight .cd, .highlight .cpf {
color: #75715e;
}
.highlight .err {
@ -137,7 +137,7 @@
.highlight .s1 {
color: #e6db74;
}
.highlight .s {
.highlight .s, .highlight .sa, .highlight .dl {
color: #e6db74;
}
.highlight .na {
@ -152,41 +152,52 @@
.highlight .ne {
color: #a6e22e;
}
.highlight .nf {
.highlight .nf, .highlight .fm {
color: #a6e22e;
}
.highlight .vc {
color: #ffffff;
background-color: #272822;
}
.highlight .nn {
color: #ffffff;
background-color: #272822;
}
.highlight .nl {
color: #ffffff;
background-color: #272822;
}
.highlight .ni {
color: #ffffff;
background-color: #272822;
}
.highlight .bp {
color: #ffffff;
background-color: #272822;
}
.highlight .vg {
color: #ffffff;
background-color: #272822;
}
.highlight .vi {
color: #ffffff;
background-color: #272822;
}
.highlight .nv {
.highlight .nv, .highlight .vm {
color: #ffffff;
background-color: #272822;
}
.highlight .w {
color: #ffffff;
background-color: #272822;
}
.highlight {
color: #ffffff;
background-color: #272822;
}
.highlight .n, .highlight .py, .highlight .nx {
color: #ffffff;
background-color: #272822;
}
.highlight .ow {
color: #f92672;
@ -216,11 +227,11 @@
<a href="#" id="nav-button">
<span>
NAV
<img src="images/navbar.png" alt="Navbar" />
<img src="images/navbar.png" alt="" />
</span>
</a>
<div class="toc-wrapper">
<img src="images/logo.png" class="logo" alt="Logo" />
<img src="images/logo.png" class="logo" alt="" />
<div class="lang-selector">
<a href="#" data-language-name="shell">cURL</a>
@ -542,13 +553,13 @@ The proper format for location tagged JSON data is:</p>
<p>Example JSON topic object:</p>
<div class="center-column"></div>
<pre class="highlight javascript tab-javascript"><code><span class="p">{</span>
<span class="s2">"value"</span><span class="p">:</span> <span class="mf">22.587</span><span class="p">,</span>
<span class="s2">"lat"</span><span class="p">:</span> <span class="mf">38.1123</span><span class="p">,</span>
<span class="s2">"lon"</span><span class="p">:</span> <span class="o">-</span><span class="mf">91.2325</span><span class="p">,</span>
<span class="s2">"ele"</span><span class="p">:</span> <span class="mi">112</span>
<div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="p">{</span>
<span class="dl">"</span><span class="s2">value</span><span class="dl">"</span><span class="p">:</span> <span class="mf">22.587</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">lat</span><span class="dl">"</span><span class="p">:</span> <span class="mf">38.1123</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">lon</span><span class="dl">"</span><span class="p">:</span> <span class="o">-</span><span class="mf">91.2325</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">ele</span><span class="dl">"</span><span class="p">:</span> <span class="mi">112</span>
<span class="p">}</span>
</code></pre>
</code></pre></div>
<p>Specifically, JSON objects must include a <code>value</code> key, and may include <code>lat</code>, <code>lon</code>, and <code>ele</code> keys.</p>
<h2 id='sending-csv'>Sending CSV</h2>
<p>Alternatively, you can send location tagged data to <code>/csv</code> topics. In this example, that would be the topic <code>mosfet/feeds/photocell-one/csv</code> instead of <code>mosfet/feeds/photocell-one</code>. Both store data in the same feed. The format IO expects for location tagged CSV data is VALUE, LATITUDE, LONGITUDE, ELEVATION.</p>
@ -558,7 +569,7 @@ The proper format for location tagged JSON data is:</p>
<p>An example is displayed below, which uses a simple Ruby MQTT library and the data shown, all these examples publish the same data to the same feed.</p>
<div class="center-column"></div>
<pre class="highlight ruby tab-ruby"><code><span class="c1"># first you'll need https://github.com/njh/ruby-mqtt</span>
<div class="highlight"><pre class="highlight ruby tab-ruby"><code><span class="c1"># first you'll need https://github.com/njh/ruby-mqtt</span>
<span class="nb">require</span> <span class="s1">'mqtt'</span>
<span class="n">username</span> <span class="o">=</span> <span class="s1">'test_username'</span>
@ -568,7 +579,7 @@ The proper format for location tagged JSON data is:</p>
<span class="n">mqtt_client</span> <span class="o">=</span> <span class="no">MQTT</span><span class="o">::</span><span class="no">Client</span><span class="p">.</span><span class="nf">connect</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="mi">8883</span><span class="p">)</span>
<span class="c1"># simplest thing that could possibly work</span>
<span class="n">mqtt_client</span><span class="p">.</span><span class="nf">publish</span><span class="p">(</span><span class="s1">'test_username/feeds/example'</span><span class="p">,</span> <span class="mi">22</span><span class="o">.</span><span class="mi">587</span><span class="p">)</span>
<span class="n">mqtt_client</span><span class="p">.</span><span class="nf">publish</span><span class="p">(</span><span class="s1">'test_username/feeds/example'</span><span class="p">,</span> <span class="mf">22.587</span><span class="p">)</span>
<span class="c1"># sending numbers as strings is fine, IO stores all data internally</span>
<span class="c1"># as strings anyways</span>
@ -590,20 +601,20 @@ The proper format for location tagged JSON data is:</p>
<span class="s1">'{"value":22.587,"lat":38.1123,"lon":-91.2325,"ele":112}'</span><span class="p">)</span>
<span class="n">mqtt_client</span><span class="p">.</span><span class="nf">publish</span><span class="p">(</span><span class="s1">'test_username/feeds/example/json'</span><span class="p">,</span>
<span class="s1">'{"value":22.587,"lat":38.1123,"lon":-91.2325,"ele":112}'</span><span class="p">)</span>
</code></pre><h2 id='sending-json-data-through-adafruit-io'>Sending JSON Data through Adafruit IO</h2>
</code></pre></div><h2 id='sending-json-data-through-adafruit-io'>Sending JSON Data through Adafruit IO</h2>
<p>Because Adafruit IO supports additional features beyond a basic MQTT brokering service, such as location tagging for data points,
the service supports data in the JSON format described above. Namely, the example JSON response on the sidebar.</p>
<p>JSON Response Format Example</p>
<div class="center-column"></div>
<pre class="highlight javascript tab-javascript"><code> <span class="p">{</span>
<span class="s2">"value"</span><span class="p">:</span> <span class="mf">22.587</span><span class="p">,</span>
<span class="s2">"lat"</span><span class="p">:</span> <span class="mf">38.1123</span><span class="p">,</span>
<span class="s2">"lon"</span><span class="p">:</span> <span class="o">-</span><span class="mf">91.2325</span><span class="p">,</span>
<span class="s2">"ele"</span><span class="p">:</span> <span class="mi">112</span>
<div class="highlight"><pre class="highlight javascript tab-javascript"><code> <span class="p">{</span>
<span class="dl">"</span><span class="s2">value</span><span class="dl">"</span><span class="p">:</span> <span class="mf">22.587</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">lat</span><span class="dl">"</span><span class="p">:</span> <span class="mf">38.1123</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">lon</span><span class="dl">"</span><span class="p">:</span> <span class="o">-</span><span class="mf">91.2325</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">ele</span><span class="dl">"</span><span class="p">:</span> <span class="mi">112</span>
<span class="p">}</span>
</code></pre>
</code></pre></div>
<p>This lets us store the individual value, <code>22.587</code>, and data about the value: its latitude, longitude, and elevation. Metadata!</p>
<p>But what happens when the value you want to send is itself JSON? Good news! There are a few solutions available to you in that situation.</p>
@ -613,13 +624,13 @@ the service supports data in the JSON format described above. Namely, the exampl
<p>Example of IO-Formatted JSON</p>
<div class="center-column"></div>
<pre class="highlight javascript tab-javascript"><code><span class="p">{</span>
<span class="s2">"value"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"sensor-1"</span><span class="p">:</span><span class="mf">22.587</span><span class="p">,</span><span class="s2">"sensor-2"</span><span class="p">:</span><span class="mf">13.182</span><span class="p">},</span>
<span class="s2">"lat"</span><span class="p">:</span> <span class="mf">38.1123</span><span class="p">,</span>
<span class="s2">"lon"</span><span class="p">:</span> <span class="o">-</span><span class="mf">91.2325</span><span class="p">,</span>
<span class="s2">"ele"</span><span class="p">:</span> <span class="mi">112</span>
<div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="p">{</span>
<span class="dl">"</span><span class="s2">value</span><span class="dl">"</span><span class="p">:</span> <span class="p">{</span><span class="dl">"</span><span class="s2">sensor-1</span><span class="dl">"</span><span class="p">:</span><span class="mf">22.587</span><span class="p">,</span><span class="dl">"</span><span class="s2">sensor-2</span><span class="dl">"</span><span class="p">:</span><span class="mf">13.182</span><span class="p">},</span>
<span class="dl">"</span><span class="s2">lat</span><span class="dl">"</span><span class="p">:</span> <span class="mf">38.1123</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">lon</span><span class="dl">"</span><span class="p">:</span> <span class="o">-</span><span class="mf">91.2325</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">ele</span><span class="dl">"</span><span class="p">:</span> <span class="mi">112</span>
<span class="p">}</span>
</code></pre>
</code></pre></div>
<p>It&#39;s worth noting that because Adafruit IO parses the entire JSON object that you send it, any valid JSON will be parsed and when it is stored in our system and forwarded to any subscribers, it will be regenerated. The significance of that is that if you publish JSON data with whitespace, it will be stored and republished without whitespace, because our generator produces the most compact JSON format possible.</p>
<h3 id='double-encoded-json-strings'>Double-Encoded JSON Strings</h3>
<p>The second way you can send JSON data as a value is to &quot;double encode&quot; it before sending, in which case IO will treat it as a raw string.
@ -629,20 +640,20 @@ If you&#39;re using something like javascript&#39;s <code>JSON.stringify</code>
<p>Here&#39;s an example of sending double-encoded strings through Adafruit IO:</p>
<div class="center-column"></div>
<pre class="highlight javascript tab-javascript"><code><span class="o">&gt;</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span><span class="s2">"sensor-1"</span><span class="p">:</span><span class="mf">22.587</span><span class="p">,</span><span class="s2">"sensor-2"</span><span class="p">:</span><span class="mf">13.182</span><span class="p">})</span>
<span class="s1">'{"sensor-1":22.587,"sensor-2":13.182}'</span>
<span class="o">&gt;</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span><span class="s2">"sensor-1"</span><span class="p">:</span><span class="mf">22.587</span><span class="p">,</span><span class="s2">"sensor-2"</span><span class="p">:</span><span class="mf">13.182</span><span class="p">}))</span>
<span class="s1">'"{\"sensor-1\":22.587,\"sensor-2\":13.182}"'</span>
</code></pre>
<div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="o">&gt;</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span><span class="dl">"</span><span class="s2">sensor-1</span><span class="dl">"</span><span class="p">:</span><span class="mf">22.587</span><span class="p">,</span><span class="dl">"</span><span class="s2">sensor-2</span><span class="dl">"</span><span class="p">:</span><span class="mf">13.182</span><span class="p">})</span>
<span class="dl">'</span><span class="s1">{"sensor-1":22.587,"sensor-2":13.182}</span><span class="dl">'</span>
<span class="o">&gt;</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span><span class="dl">"</span><span class="s2">sensor-1</span><span class="dl">"</span><span class="p">:</span><span class="mf">22.587</span><span class="p">,</span><span class="dl">"</span><span class="s2">sensor-2</span><span class="dl">"</span><span class="p">:</span><span class="mf">13.182</span><span class="p">}))</span>
<span class="dl">'</span><span class="s1">"{</span><span class="se">\</span><span class="s1">"sensor-1</span><span class="se">\</span><span class="s1">":22.587,</span><span class="se">\</span><span class="s1">"sensor-2</span><span class="se">\</span><span class="s1">":13.182}"</span><span class="dl">'</span>
</code></pre></div>
<p>The double encoded JSON string can be sent directly through Adafruit IO without interference from our processing system, because the processing system will not interpret it as JSON. In your receiving code, because the value passed through includes surrounding double quotes, you have to call your parse function twice to restore the JSON object.</p>
<p>Here&#39;s an example of interpreting double-encoded JSON Strings sent through Adafruit IO:</p>
<div class="center-column"></div>
<pre class="highlight javascript tab-javascript"><code><span class="o">&gt;</span> <span class="kd">var</span> <span class="nx">input</span> <span class="o">=</span> <span class="s1">'"{\\\"sensor-1\\\":22.587,\\\"sensor-2\\\":13.182}"'</span>
<div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="o">&gt;</span> <span class="kd">var</span> <span class="nx">input</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">"{</span><span class="se">\\\</span><span class="s1">"sensor-1</span><span class="se">\\\</span><span class="s1">":22.587,</span><span class="se">\\\</span><span class="s1">"sensor-2</span><span class="se">\\\</span><span class="s1">":13.182}"</span><span class="dl">'</span>
<span class="o">&gt;</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">input</span><span class="p">))</span>
<span class="p">{</span> <span class="s1">'sensor-1'</span><span class="p">:</span> <span class="mf">22.587</span><span class="p">,</span> <span class="s1">'sensor-2'</span><span class="p">:</span> <span class="mf">13.182</span> <span class="p">}</span>
</code></pre><h3 id='non-io-formatted-json'>Non-IO Formatted JSON</h3>
<span class="p">{</span> <span class="dl">'</span><span class="s1">sensor-1</span><span class="dl">'</span><span class="p">:</span> <span class="mf">22.587</span><span class="p">,</span> <span class="dl">'</span><span class="s1">sensor-2</span><span class="dl">'</span><span class="p">:</span> <span class="mf">13.182</span> <span class="p">}</span>
</code></pre></div><h3 id='non-io-formatted-json'>Non-IO Formatted JSON</h3>
<p>The third way you can send raw JSON data is to just send it. If Adafruit IO doesn&#39;t find a &quot;value&quot; key in the JSON object you send,
it will treat the whole blob as plain text and store and forward the data. That means with our example JSON object,
sending the string <code>{&quot;sensor-1&quot;:22.587,&quot;sensor-2&quot;:13.182}</code> will result in <code>{&quot;sensor-1&quot;:22.587,&quot;sensor-2&quot;:13.182}</code> being stored in IO and sent
@ -663,27 +674,27 @@ to MQTT subscribers.</p>
<p>If youre using the Adafruit IO Arduino library, you can add <code>/get</code> support to your project in one line of code:</p>
<div class="center-column"></div>
<pre class="highlight cpp tab-cpp"><code><span class="c1">// ... from the adafruitio_01_subscribe example sketch
</span><span class="n">AdafruitIO_Feed</span> <span class="o">*</span><span class="n">counter</span> <span class="o">=</span> <span class="n">io</span><span class="p">.</span><span class="n">feed</span><span class="p">(</span><span class="s">"counter"</span><span class="p">);</span>
<div class="highlight"><pre class="highlight cpp tab-cpp"><code><span class="c1">// ... from the adafruitio_01_subscribe example sketch</span>
<span class="n">AdafruitIO_Feed</span> <span class="o">*</span><span class="n">counter</span> <span class="o">=</span> <span class="n">io</span><span class="p">.</span><span class="n">feed</span><span class="p">(</span><span class="s">"counter"</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// 1. start IO connection
</span> <span class="n">io</span><span class="p">.</span><span class="n">connect</span><span class="p">();</span>
<span class="c1">// 1. start IO connection</span>
<span class="n">io</span><span class="p">.</span><span class="n">connect</span><span class="p">();</span>
<span class="c1">// 2. prepare MQTT subscription with handler function
</span> <span class="n">counter</span><span class="o">-&gt;</span><span class="n">onMessage</span><span class="p">(</span><span class="n">handleMessage</span><span class="p">);</span>
<span class="c1">// 2. prepare MQTT subscription with handler function</span>
<span class="n">counter</span><span class="o">-&gt;</span><span class="n">onMessage</span><span class="p">(</span><span class="n">handleMessage</span><span class="p">);</span>
<span class="c1">// 3. wait for successful connection
</span> <span class="k">while</span><span class="p">(</span><span class="n">io</span><span class="p">.</span><span class="n">mqttStatus</span><span class="p">()</span> <span class="o">&lt;</span> <span class="n">AIO_CONNECTED</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// 3. wait for successful connection</span>
<span class="k">while</span><span class="p">(</span><span class="n">io</span><span class="p">.</span><span class="n">mqttStatus</span><span class="p">()</span> <span class="o">&lt;</span> <span class="n">AIO_CONNECTED</span><span class="p">)</span> <span class="p">{</span>
<span class="n">delay</span><span class="p">(</span><span class="mi">500</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// 4. send /get message, requesting last value, triggering
</span> <span class="c1">// the handleMessage handler function
</span> <span class="n">counter</span><span class="o">-&gt;</span><span class="n">get</span><span class="p">();</span> <span class="c1">// ask Adafruit IO to resend the last value
</span><span class="p">}</span>
<span class="c1">// ....
</span></code></pre>
<span class="c1">// 4. send /get message, requesting last value, triggering</span>
<span class="c1">// the handleMessage handler function</span>
<span class="n">counter</span><span class="o">-&gt;</span><span class="n">get</span><span class="p">();</span> <span class="c1">// ask Adafruit IO to resend the last value</span>
<span class="p">}</span>
<span class="c1">// ....</span>
</code></pre></div>
<p>You can also perform a <code>/get</code> using the Adafruit IO CircuitPython library in one line of code:
<div class="center-column"></div>
<code>python
@ -746,27 +757,27 @@ can subscribe to a feed&#39;s topic to be notified when the feed has a new value
<p>JSON Expected Response from Adafruit IO</p>
<div class="center-column"></div>
<pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="s2">"feeds"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"key-1"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value 1"</span><span class="p">,</span><span class="w">
</span><span class="s2">"key-2"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value 2"</span><span class="p">,</span><span class="w">
</span><span class="s2">"key-3"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value 3"</span><span class="w">
<div class="highlight"><pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="nl">"feeds"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"key-1"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value 1"</span><span class="p">,</span><span class="w">
</span><span class="nl">"key-2"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value 2"</span><span class="p">,</span><span class="w">
</span><span class="nl">"key-3"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value 3"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="s2">"location"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"lat"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0</span><span class="p">,</span><span class="w">
</span><span class="s2">"lon"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0</span><span class="p">,</span><span class="w">
</span><span class="s2">"ele"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0</span><span class="w">
</span><span class="nl">"location"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"lat"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0</span><span class="p">,</span><span class="w">
</span><span class="nl">"lon"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0</span><span class="p">,</span><span class="w">
</span><span class="nl">"ele"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre>
</span></code></pre></div>
<p>CSV Format Expected Response from Adafruit IO</p>
<div class="center-column"></div>
<pre class="highlight plaintext"><code>key-1,value 1
<div class="highlight"><pre class="highlight plaintext"><code>key-1,value 1
key-2,value 2
key-3,value 3
location,0.0,0.0,0.0
</code></pre><h2 id='group-guidelines'>Group Guidelines</h2>
</code></pre></div><h2 id='group-guidelines'>Group Guidelines</h2>
<ul>
<li> In each payload format, <code>key-1</code> represents the respective feed&#39;s key and <code>value 1</code> represents the value you&#39;d like to publish to that feed.</li>
<li> For CSV location values, the location is interpreted as <code>lat</code>, <code>lon</code>, <code>ele</code> and <code>ele</code> is optional <code>/</code> not required.</li>
@ -782,36 +793,36 @@ location,0.0,0.0,0.0
<p>Expected Group JSON Response</p>
<div class="center-column"></div>
<pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="s2">"feeds"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"key-1"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value 1"</span><span class="p">,</span><span class="w">
</span><span class="s2">"key-2"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value 2"</span><span class="p">,</span><span class="w">
</span><span class="s2">"key-3"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value 3"</span><span class="w">
<div class="highlight"><pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="nl">"feeds"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"key-1"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value 1"</span><span class="p">,</span><span class="w">
</span><span class="nl">"key-2"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value 2"</span><span class="p">,</span><span class="w">
</span><span class="nl">"key-3"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value 3"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="s2">"location"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"lat"</span><span class="p">:</span><span class="w"> </span><span class="mf">1.0</span><span class="p">,</span><span class="w">
</span><span class="s2">"lon"</span><span class="p">:</span><span class="w"> </span><span class="mf">2.0</span><span class="p">,</span><span class="w">
</span><span class="s2">"ele"</span><span class="p">:</span><span class="w"> </span><span class="mf">3.0</span><span class="w">
</span><span class="nl">"location"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"lat"</span><span class="p">:</span><span class="w"> </span><span class="mf">1.0</span><span class="p">,</span><span class="w">
</span><span class="nl">"lon"</span><span class="p">:</span><span class="w"> </span><span class="mf">2.0</span><span class="p">,</span><span class="w">
</span><span class="nl">"ele"</span><span class="p">:</span><span class="w"> </span><span class="mf">3.0</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre>
</span></code></pre></div>
<p>Expected Group CSV Response</p>
<div class="center-column"></div>
<pre class="highlight plaintext"><code>key-1,value 1
<div class="highlight"><pre class="highlight plaintext"><code>key-1,value 1
key-2,value 2
key-3,value 3
location,1.0,2.0,3.0
</code></pre>
</code></pre></div>
<p>It&#39;s important to note that you will only receive updated values for the feeds that received new values. That means if you&#39;re subscribed to <code>{username}/groups/example</code> and publish to <code>{username}/feeds/key-1</code>, the subscription will receive:</p>
<div class="center-column"></div>
<pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="s2">"feeds"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"key-1"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value 1"</span><span class="w">
<div class="highlight"><pre class="highlight json tab-json"><code><span class="p">{</span><span class="w">
</span><span class="nl">"feeds"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"key-1"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value 1"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre>
</span></code></pre></div>
<p>It&#39;s also worth noting that JSON subscription formats will always receive string type values, regardless of whether a string or number was published.</p>
<h1 id='time-topics'>Time Topics</h1>
<p>Adafruit IO provides some built-in MQTT topics for getting the current server time. The current available topics are:</p>
@ -828,7 +839,7 @@ location,1.0,2.0,3.0
<ul>
<li><a href="https://github.com/adafruit/Adafruit_IO_Arduino/blob/master/examples/adafruitio_17_time_subscribe/adafruitio_17_time_subscribe.ino">Arduino</a></li>
<li><a href="https://github.com/adafruit/Adafruit_IO_Python/blob/master/examples/mqtt/mqtt_time.py">Python</a></li>
<li><a href="https://github.com/adafruit/Adafruit_CircuitPython_AdafruitIO/blob/master/examples/mqtt/adafruit_io_time.py">CircuitPython</a></li>
<li><a href="https://github.com/adafruit/Adafruit_CircuitPython_AdafruitIO/blob/master/examples/adafruit_io_mqtt/adafruit_io_time.py">CircuitPython</a></li>
</ul>
<h2 id='time-seconds'>time/seconds</h2>
<p>This topic publishes the current time in <a href="https://en.wikipedia.org/wiki/Unix_time">Unix epoch seconds</a>.</p>

View file

@ -11,6 +11,7 @@
src: url("../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"), url("../fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"), url("../fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"), url("../fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"), url("../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg");
font-weight: normal;
font-style: normal; }
.fa {
display: inline-block;
font: normal normal normal 14px/1 FontAwesome;
@ -21,7 +22,7 @@
/* makes the font 33% larger relative to the icon container */
.fa-lg {
font-size: 1.33333em;
font-size: 1.3333333333em;
line-height: 0.75em;
vertical-align: -15%; }
@ -38,24 +39,24 @@
font-size: 5em; }
.fa-fw {
width: 1.28571em;
width: 1.2857142857em;
text-align: center; }
.fa-ul {
padding-left: 0;
margin-left: 2.14286em;
margin-left: 2.1428571429em;
list-style-type: none; }
.fa-ul > li {
position: relative; }
.fa-li {
position: absolute;
left: -2.14286em;
width: 2.14286em;
top: 0.14286em;
left: -2.1428571429em;
width: 2.1428571429em;
top: 0.1428571429em;
text-align: center; }
.fa-li.fa-lg {
left: -1.85714em; }
left: -1.8571428571em; }
.fa-border {
padding: .2em .25em .15em;
@ -70,6 +71,7 @@
.fa.fa-pull-left {
margin-right: .3em; }
.fa.fa-pull-right {
margin-left: .3em; }
@ -82,6 +84,7 @@
.fa.pull-left {
margin-right: .3em; }
.fa.pull-right {
margin-left: .3em; }
@ -100,6 +103,7 @@
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg); } }
@keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
@ -107,6 +111,7 @@
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg); } }
.fa-rotate-90 {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
-webkit-transform: rotate(90deg);

View file

@ -1 +1 @@
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.content h1,.content h2,.content h3,.content h4,body{font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size:14px}.content h1,.content h2,.content h3,.content h4{font-weight:bold}.content pre,.content code{font-family:Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, serif;font-size:12px;line-height:1.5}.content pre,.content code{word-break:break-all;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto}@font-face{font-family:'slate';src:url(../fonts/slate.eot?-syv14m);src:url(../fonts/slate.eot?#iefix-syv14m) format("embedded-opentype"),url(../fonts/slate.woff2?-syv14m) format("woff2"),url(../fonts/slate.woff?-syv14m) format("woff"),url(../fonts/slate.ttf?-syv14m) format("truetype"),url(../fonts/slate.svg?-syv14m#slate) format("svg");font-weight:normal;font-style:normal}.content aside.warning:before,.content aside.notice:before,.content aside.success:before{font-family:'slate';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1}.content aside.warning:before{content:"\e600"}.content aside.notice:before{content:"\e602"}.content aside.success:before{content:"\e606"}.tocify,.toc-footer,.lang-selector,.search,#nav-button{display:none}.tocify-wrapper>img{margin:0 auto;display:block}.content{font-size:12px}.content pre,.content code{border:1px solid #999;border-radius:5px;font-size:0.8em}.content pre code{border:0}.content pre{padding:1.3em}.content code{padding:0.2em}.content table{border:1px solid #999}.content table tr{border-bottom:1px solid #999}.content table td,.content table th{padding:0.7em}.content p{line-height:1.5}.content a{text-decoration:none;color:#000}.content h1{font-size:2.5em;padding-top:0.5em;padding-bottom:0.5em;margin-top:1em;margin-bottom:21px;border:2px solid #ccc;border-width:2px 0;text-align:center}.content h2{font-size:1.8em;margin-top:2em;border-top:2px solid #ccc;padding-top:0.8em}.content h1+h2,.content h1+div+h2{border-top:none;padding-top:0;margin-top:0}.content h3,.content h4{font-size:0.8em;margin-top:1.5em;margin-bottom:0.8em;text-transform:uppercase}.content h5,.content h6{text-transform:uppercase}.content aside{padding:1em;border:1px solid #ccc;border-radius:5px;margin-top:1.5em;margin-bottom:1.5em;line-height:1.6}.content aside:before{vertical-align:middle;padding-right:0.5em;font-size:14px}
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}body,.content h3,.content h4,.content h2,.content h1{font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size:14px}.content h3,.content h4,.content h2,.content h1{font-weight:bold}.content pre,.content code{font-family:Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, serif;font-size:12px;line-height:1.5}.content pre,.content code{word-break:break-all;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto}@font-face{font-family:'slate';src:url("../fonts/slate.eot?-syv14m");src:url("../fonts/slate.eot?#iefix-syv14m") format("embedded-opentype"),url("../fonts/slate.woff2?-syv14m") format("woff2"),url("../fonts/slate.woff?-syv14m") format("woff"),url("../fonts/slate.ttf?-syv14m") format("truetype"),url("../fonts/slate.svg?-syv14m#slate") format("svg");font-weight:normal;font-style:normal}.content aside.success:before,.content aside.notice:before,.content aside.warning:before{font-family:'slate';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1}.content aside.warning:before{content:"\e600"}.content aside.notice:before{content:"\e602"}.content aside.success:before{content:"\e606"}.tocify,.toc-footer,.lang-selector,.search,#nav-button{display:none}.tocify-wrapper>img{margin:0 auto;display:block}.content{font-size:12px}.content pre,.content code{border:1px solid #999;border-radius:5px;font-size:0.8em}.content pre code{border:0}.content pre{padding:1.3em}.content code{padding:0.2em}.content table{border:1px solid #999}.content table tr{border-bottom:1px solid #999}.content table td,.content table th{padding:0.7em}.content p{line-height:1.5}.content a{text-decoration:none;color:#000}.content h1{font-size:2.5em;padding-top:0.5em;padding-bottom:0.5em;margin-top:1em;margin-bottom:21px;border:2px solid #ccc;border-width:2px 0;text-align:center}.content h2{font-size:1.8em;margin-top:2em;border-top:2px solid #ccc;padding-top:0.8em}.content h1+h2,.content h1+div+h2{border-top:none;padding-top:0;margin-top:0}.content h3,.content h4{font-size:0.8em;margin-top:1.5em;margin-bottom:0.8em;text-transform:uppercase}.content h5,.content h6{text-transform:uppercase}.content aside{padding:1em;border:1px solid #ccc;border-radius:5px;margin-top:1.5em;margin-bottom:1.5em;line-height:1.6}.content aside:before{vertical-align:middle;padding-right:0.5em;font-size:14px}

File diff suppressed because one or more lines are too long