Compare commits

...

No commits in common. "main" and "gh-pages" have entirely different histories.

139 changed files with 9337 additions and 22608 deletions

10
.github/main.workflow vendored
View file

@ -1,10 +0,0 @@
workflow "New workflow" {
on = "page_build"
resolves = ["GitHub Action for Slack"]
}
action "GitHub Action for Slack" {
uses = "Ilshidur/action-slack@e820f544affdbb77c1dee6d3f752f7f2daf4a0b3"
secrets = ["SLACK_WEBHOOK"]
args = "The GitHub Page has been built by {{ EVENT_PAYLOAD.build.pusher.login }}"
}

View file

@ -1,39 +0,0 @@
name: Deploy
on:
push:
branches: [ 'main' ]
jobs:
deploy:
runs-on: ubuntu-latest
env:
ruby-version: 3.2.2
steps:
- uses: actions/checkout@v2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ env.ruby-version }}
- uses: actions/cache@v4
with:
path: vendor/bundle
key: gems-${{ runner.os }}-${{ matrix.ruby-version }}-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
gems-${{ runner.os }}-${{ matrix.ruby-version }}-
gems-${{ runner.os }}-
- run: bundle config set deployment 'true'
- name: bundle install
run: |
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3
- run: bundle exec middleman build
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./build
keep_files: true

5
.gitignore vendored
View file

@ -1,5 +0,0 @@
build/
.gvimrc
.DS_Store
.sass-cache

0
.nojekyll Normal file
View file

View file

@ -1,162 +0,0 @@
# Changelog
## Version 2.3.1
*July 5, 2018*
- Update `sprockets` in `Gemfile.lock` to fix security warnings
## Version 2.3
*July 5, 2018*
- Allows strikethrough in markdown by default.
- Upgrades jQuery to 3.2.1, thanks to [Tomi Takussaari](https://github.com/TomiTakussaari)
- Fixes invalid HTML in `layout.erb`, thanks to [Eric Scouten](https://github.com/scouten) for pointing out
- Hopefully fixes Vagrant memory issues, thanks to [Petter Blomberg](https://github.com/p-blomberg) for the suggestion
- Cleans HTML in headers before setting `document.title`, thanks to [Dan Levy](https://github.com/justsml)
- Allows trailing whitespace in markdown files, thanks to [Samuel Cousin](https://github.com/kuzyn)
- Fixes pushState/replaceState problems with scrolling not changing the document hash, thanks to [Andrey Fedorov](https://github.com/anfedorov)
- Removes some outdated examples, thanks [@al-tr](https://github.com/al-tr), [Jerome Dahdah](https://github.com/jdahdah), and [Ricardo Castro](https://github.com/mccricardo)
- Fixes `nav-padding` bug, thanks [Jerome Dahdah](https://github.com/jdahdah)
- Code style fixes thanks to [Sebastian Zaremba](https://github.com/vassyz)
- Nokogiri version bump thanks to [Grey Baker](https://github.com/greysteil)
- Fix to default `index.md` text thanks to [Nick Busey](https://github.com/NickBusey)
Thanks to everyone who contributed to this release!
## Version 2.2
*January 19, 2018*
- Fixes bugs with some non-roman languages not generating unique headers
- Adds editorconfig, thanks to [Jay Thomas](https://github.com/jaythomas)
- Adds optional `NestingUniqueHeadCounter`, thanks to [Vladimir Morozov](https://github.com/greenhost87)
- Small fixes to typos and language, thx [Emir Ribić](https://github.com/ribice), [Gregor Martynus](https://github.com/gr2m), and [Martius](https://github.com/martiuslim)!
- Adds links to Spectrum chat for questions in README and ISSUE_TEMPLATE
## Version 2.1
*October 30, 2017*
- Right-to-left text stylesheet option, thanks to [Mohammad Hossein Rabiee](https://github.com/mhrabiee)
- Fix for HTML5 history state bug, thanks to [Zach Toolson](https://github.com/ztoolson)
- Small styling changes, typo fixes, small bug fixes from [Marian Friedmann](https://github.com/rnarian), [Ben Wilhelm](https://github.com/benwilhelm), [Fouad Matin](https://github.com/fouad), [Nicolas Bonduel](https://github.com/NicolasBonduel), [Christian Oliff](https://github.com/coliff)
Thanks to everyone who submitted PRs for this version!
## Version 2.0
*July 17, 2017*
- All-new statically generated table of contents
- Should be much faster loading and scrolling for large pages
- Smaller Javascript file sizes
- Avoids the problem with the last link in the ToC not ever highlighting if the section was shorter than the page
- Fixes control-click not opening in a new page
- Automatically updates the HTML title as you scroll
- Updated design
- New default colors!
- New spacings and sizes!
- System-default typefaces, just like GitHub
- Added search input delay on large corpuses to reduce lag
- We even bumped the major version cause hey, why not?
- Various small bug fixes
Thanks to everyone who helped debug or wrote code for this version! It was a serious community effort, and I couldn't have done it alone.
## Version 1.5
*February 23, 2017*
- Add [multiple tabs per programming language](https://github.com/lord/slate/wiki/Multiple-language-tabs-per-programming-language) feature
- Upgrade Middleman to add Ruby 1.4.0 compatibility
- Switch default code highlighting color scheme to better highlight JSON
- Various small typo and bug fixes
## Version 1.4
*November 24, 2016*
- Upgrade Middleman and Rouge gems, should hopefully solve a number of bugs
- Update some links in README
- Fix broken Vagrant startup script
- Fix some problems with deploy.sh help message
- Fix bug with language tabs not hiding properly if no error
- Add `!default` to SASS variables
- Fix bug with logo margin
- Bump tested Ruby versions in .travis.yml
## Version 1.3.3
*June 11, 2016*
Documentation and example changes.
## Version 1.3.2
*February 3, 2016*
A small bugfix for slightly incorrect background colors on code samples in some cases.
## Version 1.3.1
*January 31, 2016*
A small bugfix for incorrect whitespace in code blocks.
## Version 1.3
*January 27, 2016*
We've upgraded Middleman and a number of other dependencies, which should fix quite a few bugs.
Instead of `rake build` and `rake deploy`, you should now run `bundle exec middleman build --clean` to build your server, and `./deploy.sh` to deploy it to Github Pages.
## Version 1.2
*June 20, 2015*
**Fixes:**
- Remove crash on invalid languages
- Update Tocify to scroll to the highlighted header in the Table of Contents
- Fix variable leak and update search algorithms
- Update Python examples to be valid Python
- Update gems
- More misc. bugfixes of Javascript errors
- Add Dockerfile
- Remove unused gems
- Optimize images, fonts, and generated asset files
- Add chinese font support
- Remove RedCarpet header ID patch
- Update language tabs to not disturb existing query strings
## Version 1.1
*July 27, 2014*
**Fixes:**
- Finally, a fix for the redcarpet upgrade bug
## Version 1.0
*July 2, 2014*
[View Issues](https://github.com/tripit/slate/issues?milestone=1&state=closed)
**Features:**
- Responsive designs for phones and tablets
- Started tagging versions
**Fixes:**
- Fixed 'unrecognized expression' error
- Fixed #undefined hash bug
- Fixed bug where the current language tab would be unselected
- Fixed bug where tocify wouldn't highlight the current section while searching
- Fixed bug where ids of header tags would have special characters that caused problems
- Updated layout so that pages with disabled search wouldn't load search.js
- Cleaned up Javascript

View file

@ -1,46 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@lord.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View file

@ -1,13 +0,0 @@
FROM ruby:3.2.2
COPY . /usr/src/app
VOLUME /usr/src/app
EXPOSE 4567
WORKDIR /usr/src/app
RUN apt-get update && apt-get install -y nodejs \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
RUN gem install bundler:2.1.4
RUN bundle install
CMD ["bundle", "exec", "middleman", "server", "--watcher-force-polling", "--verbose"]

17
Gemfile
View file

@ -1,17 +0,0 @@
ruby '>= 3.2.2'
source 'https://rubygems.org'
# Middleman
gem 'ffi', '~> 1.16.3'
gem 'middleman', '~> 4.5.0'
gem 'middleman-autoprefixer', '~> 3.0.0'
gem 'middleman-sprockets', '~> 4.1.1'
gem 'middleman-syntax', '~> 3.2.0'
gem 'nokogiri', '~> 1.18.8'
gem 'rack', '~> 2.2.13'
gem 'redcarpet', '~> 3.6.0'
gem 'rouge', '~> 3.30.0'
# middleman-syntax won't work with haml6
# See: https://github.com/middleman/middleman-syntax/issues/80
gem 'haml', '< 6.0.0'

View file

@ -1,139 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (7.0.8)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
autoprefixer-rails (10.4.15.0)
execjs (~> 2)
backports (3.24.1)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.12.2)
concurrent-ruby (1.2.2)
contracts (0.16.1)
dotenv (2.8.1)
erubis (2.7.0)
execjs (2.9.1)
fast_blank (1.0.1)
fastimage (2.2.7)
ffi (1.16.3)
haml (5.2.2)
temple (>= 0.8.0)
tilt
hamster (3.0.0)
concurrent-ruby (~> 1.0)
hashie (3.6.0)
i18n (1.6.0)
concurrent-ruby (~> 1.0)
kramdown (2.4.0)
rexml
listen (3.8.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
memoist (0.16.2)
middleman (4.5.0)
coffee-script (~> 2.2)
haml (>= 4.0.5)
kramdown (>= 2.3.0)
middleman-cli (= 4.5.0)
middleman-core (= 4.5.0)
middleman-autoprefixer (3.0.0)
autoprefixer-rails (~> 10.0)
middleman-core (>= 4.0.0)
middleman-cli (4.5.0)
thor (>= 0.17.0, < 2.0)
middleman-core (4.5.0)
activesupport (>= 6.1, < 7.1)
addressable (~> 2.4)
backports (~> 3.6)
bundler (~> 2.0)
contracts (~> 0.13)
dotenv
erubis
execjs (~> 2.0)
fast_blank
fastimage (~> 2.0)
hamster (~> 3.0)
hashie (~> 3.4)
i18n (~> 1.6.0)
listen (~> 3.0)
memoist (~> 0.14)
padrino-helpers (~> 0.15.0)
parallel
rack (>= 1.4.5, < 3)
sassc (~> 2.0)
servolux
tilt (~> 2.0.9)
toml
uglifier (~> 3.0)
webrick
middleman-sprockets (4.1.1)
middleman-core (~> 4.0)
sprockets (>= 3.0)
middleman-syntax (3.2.0)
middleman-core (>= 3.2)
rouge (~> 3.2)
mini_portile2 (2.8.8)
minitest (5.20.0)
nokogiri (1.18.8)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
padrino-helpers (0.15.3)
i18n (>= 0.6.7, < 2)
padrino-support (= 0.15.3)
tilt (>= 1.4.1, < 3)
padrino-support (0.15.3)
parallel (1.23.0)
parslet (2.0.0)
public_suffix (5.0.3)
racc (1.8.1)
rack (2.2.13)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
redcarpet (3.6.0)
rexml (3.3.9)
rouge (3.30.0)
sassc (2.4.0)
ffi (~> 1.9)
servolux (0.13.0)
sprockets (4.0.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
temple (0.10.3)
thor (1.2.2)
tilt (2.0.11)
toml (0.3.0)
parslet (>= 1.8.0, < 3.0.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uglifier (3.2.0)
execjs (>= 0.3.0, < 3)
webrick (1.8.2)
PLATFORMS
ruby
DEPENDENCIES
ffi (~> 1.16.3)
haml (< 6.0.0)
middleman (~> 4.5.0)
middleman-autoprefixer (~> 3.0.0)
middleman-sprockets (~> 4.1.1)
middleman-syntax (~> 3.2.0)
nokogiri (~> 1.18.8)
rack (~> 2.2.13)
redcarpet (~> 3.6.0)
rouge (~> 3.30.0)
RUBY VERSION
ruby 3.2.2p53
BUNDLED WITH
2.1.4

13
LICENSE
View file

@ -1,13 +0,0 @@
Copyright 2008-2013 Concur Technologies, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.

View file

@ -1,45 +0,0 @@
# Adafruit IO API Documentation
Repository of documentation for Adafruit IO's HTTP and MQTT API. This is a fork of the [Slate documentation project](https://github.com/lord/slate). Slate is a set of templates and conventions applied to [the middleman static site generator](https://middlemanapp.com/), so our documentation source mostly [markdown formatted text](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) and some Ruby, but the output is static HTML, css, and javascript.
You can visit the live documentation site at https://io.adafruit.com/api/docs/#adafruit-io
## Building locally
To build this project locally:
1. Fork this repository on GitHub.
2. Clone your *forked* repository:
`git clone git@github.com:YOURUSERNAME/Adafruit_IO_Documentation.git`
3. `cd Adafruit_IO_Documentation`
4. Next, you can initialize and start Slate. You can either do this with [Docker](https://www.docker.com) or [Vagrant](https://www.vagrantup.com).
### using Docker
To run Slate:
`docker-compose up`
The API documentation will be located at [http://localhost:4567/](http://localhost:4567/)
Building a static copy of the documentation into `build`:
`docker run --rm -v $PWD:/usr/src/app/source -w /usr/src/app/source slate_app bundle exec middleman build --clean`
### using Vagrant
To run slate:
`vagrant up`.
## Contributing
Contributions are welcome!
This project is based on [slate](https://github.com/lord/slate). All source for the documentation sections are in Markdown formatted text files in the [source/includes](https://github.com/adafruit/Adafruit_IO_Documentation/tree/master/source/includes) directory.
If you see a change you'd like to make, you can fork this repository, commit your changes to your copy of the project, and submit it as a pull request. If you have a question or find that something is missing or incorrectly documented, you can let us know by [creating a new issue](https://github.com/adafruit/Adafruit_IO_Documentation/issues) on this project.

44
Vagrantfile vendored
View file

@ -1,44 +0,0 @@
Vagrant.configure(2) do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.network :forwarded_port, guest: 4567, host: 4567
config.vm.provider "virtualbox" do |vb|
vb.memory = "2048"
end
config.vm.provision "bootstrap",
type: "shell",
inline: <<-SHELL
sudo apt-add-repository ppa:brightbox/ruby-ng
sudo apt-get update
sudo apt-get install -yq ruby2.4 ruby2.4-dev
sudo apt-get install -yq pkg-config build-essential nodejs git libxml2-dev libxslt-dev
sudo apt-get autoremove -yq
gem2.4 install --no-ri --no-rdoc bundler
SHELL
# add the local user git config to the vm
config.vm.provision "file", source: "~/.gitconfig", destination: ".gitconfig"
config.vm.provision "install",
type: "shell",
privileged: false,
inline: <<-SHELL
echo "=============================================="
echo "Installing app dependencies"
cd /vagrant
bundle config build.nokogiri --use-system-libraries
bundle install
SHELL
config.vm.provision "run",
type: "shell",
privileged: false,
run: "always",
inline: <<-SHELL
echo "=============================================="
echo "Starting up middleman at http://localhost:4567"
echo "If it does not come up, check the ~/middleman.log file for any error messages"
cd /vagrant
bundle exec middleman server --watcher-force-polling --watcher-latency=1 &> ~/middleman.log &
SHELL
end

View file

@ -1,61 +0,0 @@
# Unique header generation
require './lib/unique_head.rb'
# Markdown
set :markdown_engine, :redcarpet
set :markdown,
fenced_code_blocks: true,
smartypants: true,
disable_indented_code_blocks: true,
prettify: true,
strikethrough: true,
tables: true,
with_toc_data: true,
no_intra_emphasis: true,
renderer: UniqueHeadCounter
# Assets
set :css_dir, 'stylesheets'
set :js_dir, 'javascripts'
set :images_dir, 'images'
set :fonts_dir, 'fonts'
# Activate the syntax highlighter
activate :syntax
ready do
require './lib/multilang.rb'
end
activate :sprockets do |sprockets|
sprockets.supported_output_extensions = ['.js']
end
activate :autoprefixer do |config|
config.browsers = ['last 2 version', 'Firefox ESR']
config.cascade = false
config.inline = true
end
# Github pages require relative links
activate :relative_assets
set :relative_links, true
# Build Configuration
configure :build do
# If you're having trouble with Middleman hanging, commenting
# out the following two lines has been known to help
activate :minify_css
activate :minify_javascript
# activate :relative_assets
# activate :asset_hash
# activate :gzip
end
# Deploy Configuration
# If you want Middleman to listen on a different port, you can set that below
set :port, 4567
helpers do
require './lib/toc_data.rb'
require './lib/messages.rb'
end

541
cookbook.html Normal file
View file

@ -0,0 +1,541 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>Adafruit IO API Cookbook</title>
<link href="images/favicon/favicon.ico" rel="icon" type="image/ico" />
<link rel="apple-touch-icon" sizes="180x180" href="images/favicon/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="images/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="images/favicon/favicon-16x16.png">
<link rel="manifest" href="images/favicon/site.webmanifest">
<link rel="mask-icon" href="images/favicon/safari-pinned-tab.svg" color="#00A7E9">
<meta name="msapplication-TileColor" content="#00A7E9">
<meta name="theme-color" content="#000000">
<style>
.highlight table td { padding: 5px; }
.highlight table pre { margin: 0; }
.highlight .gh {
color: #999999;
}
.highlight .sr {
color: #f6aa11;
}
.highlight .go {
color: #888888;
}
.highlight .gp {
color: #555555;
}
.highlight .gs {
}
.highlight .gu {
color: #aaaaaa;
}
.highlight .nb {
color: #f6aa11;
}
.highlight .cm {
color: #75715e;
}
.highlight .cp {
color: #75715e;
}
.highlight .c1 {
color: #75715e;
}
.highlight .cs {
color: #75715e;
}
.highlight .c, .highlight .ch, .highlight .cd, .highlight .cpf {
color: #75715e;
}
.highlight .err {
color: #960050;
}
.highlight .gr {
color: #960050;
}
.highlight .gt {
color: #960050;
}
.highlight .gd {
color: #49483e;
}
.highlight .gi {
color: #49483e;
}
.highlight .ge {
color: #49483e;
}
.highlight .kc {
color: #66d9ef;
}
.highlight .kd {
color: #66d9ef;
}
.highlight .kr {
color: #66d9ef;
}
.highlight .no {
color: #66d9ef;
}
.highlight .kt {
color: #66d9ef;
}
.highlight .mf {
color: #ae81ff;
}
.highlight .mh {
color: #ae81ff;
}
.highlight .il {
color: #ae81ff;
}
.highlight .mi {
color: #ae81ff;
}
.highlight .mo {
color: #ae81ff;
}
.highlight .m, .highlight .mb, .highlight .mx {
color: #ae81ff;
}
.highlight .sc {
color: #ae81ff;
}
.highlight .se {
color: #ae81ff;
}
.highlight .ss {
color: #ae81ff;
}
.highlight .sd {
color: #e6db74;
}
.highlight .s2 {
color: #e6db74;
}
.highlight .sb {
color: #e6db74;
}
.highlight .sh {
color: #e6db74;
}
.highlight .si {
color: #e6db74;
}
.highlight .sx {
color: #e6db74;
}
.highlight .s1 {
color: #e6db74;
}
.highlight .s, .highlight .sa, .highlight .dl {
color: #e6db74;
}
.highlight .na {
color: #a6e22e;
}
.highlight .nc {
color: #a6e22e;
}
.highlight .nd {
color: #a6e22e;
}
.highlight .ne {
color: #a6e22e;
}
.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 .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;
}
.highlight .nt {
color: #f92672;
}
.highlight .k, .highlight .kv {
color: #f92672;
}
.highlight .kn {
color: #f92672;
}
.highlight .kp {
color: #f92672;
}
.highlight .o {
color: #f92672;
}
</style>
<link href="stylesheets/screen.css" rel="stylesheet" media="screen" />
<link href="stylesheets/print.css" rel="stylesheet" media="print" />
<script src="javascripts/all.js"></script>
</head>
<body class="cookbook" data-languages="[&quot;shell&quot;,&quot;cpp&quot;,&quot;python&quot;,&quot;python&quot;,&quot;ruby&quot;]">
<a href="#" id="nav-button">
<span>
NAV
<img src="images/navbar.png" alt="" />
</span>
</a>
<div class="toc-wrapper">
<img src="images/logo.png" class="logo" alt="" />
<div class="lang-selector">
<a href="#" data-language-name="shell">CURL</a>
<a href="#" data-language-name="cpp">Arduino</a>
<a href="#" data-language-name="python">Python</a>
<a href="#" data-language-name="python">Circuitpython</a>
<a href="#" data-language-name="ruby">Ruby</a>
</div>
<div class="search">
<input type="text" class="search" id="input-search" placeholder="Search">
</div>
<ul class="search-results"></ul>
<ul id="toc" class="toc-list-h1">
<li>
<a href="./" class="toc-h1 toc-link prepend"> Adafruit IO HTTP API
<i class="fa fa-external-link"></i>
</a> </li>
<li>
<a href="mqtt.html" class="toc-h1 toc-link prepend"> Adafruit IO MQTT API
<i class="fa fa-external-link"></i>
</a> </li>
<li class="on-screen">
<a href="#adafruit-io-api-cookbook" class="toc-h1 toc-link" data-title="Adafruit IO API Cookbook">
Adafruit IO API Cookbook
</a>
</li>
<li class="on-screen">
<a href="#feed-identifiers" class="toc-h1 toc-link" data-title="Feed Identifiers">
Feed Identifiers
</a>
</li>
<li class="on-screen">
<a href="#formatting-values" class="toc-h1 toc-link" data-title="Formatting values">
Formatting values
<span class="menu-arrow">
<svg width="18" height="18" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1171 960q0 13-10 23l-466 466q-10 10-23 10t-23-10l-50-50q-10-10-10-23t10-23l393-393-393-393q-10-10-10-23t10-23l50-50q10-10 23-10t23 10l466 466q10 10 10 23z"/></svg>
<!-- <span>&gt;</span> -->
</span>
</a>
<ul class="toc-list-h2">
<li>
<a href="#floating-point-data" class="toc-h2 toc-link" data-title="Floating Point Data">Floating Point Data</a>
</li>
</ul>
</li>
<li class="on-screen">
<a href="#image-data" class="toc-h1 toc-link" data-title="Image Data">
Image Data
<span class="menu-arrow">
<svg width="18" height="18" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1171 960q0 13-10 23l-466 466q-10 10-23 10t-23-10l-50-50q-10-10-10-23t10-23l393-393-393-393q-10-10-10-23t10-23l50-50q10-10 23-10t23 10l466 466q10 10 10 23z"/></svg>
<!-- <span>&gt;</span> -->
</span>
</a>
<ul class="toc-list-h2">
<li>
<a href="#design-considerations" class="toc-h2 toc-link" data-title="Design Considerations">Design Considerations</a>
</li>
<li>
<a href="#publishing-image-data" class="toc-h2 toc-link" data-title="Publishing Image Data">Publishing Image Data</a>
</li>
</ul>
</li>
<li class="on-screen">
<a href="#sending-and-storing-json" class="toc-h1 toc-link" data-title="Sending and Storing JSON">
Sending and Storing JSON
<span class="menu-arrow">
<svg width="18" height="18" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1171 960q0 13-10 23l-466 466q-10 10-23 10t-23-10l-50-50q-10-10-10-23t10-23l393-393-393-393q-10-10-10-23t10-23l50-50q10-10 23-10t23 10l466 466q10 10 10 23z"/></svg>
<!-- <span>&gt;</span> -->
</span>
</a>
<ul class="toc-list-h2">
<li>
<a href="#double-encoded-json-strings" class="toc-h2 toc-link" data-title="Double encoded JSON strings">Double encoded JSON strings</a>
</li>
<li>
<a href="#io-formatted-json" class="toc-h2 toc-link" data-title="IO formatted JSON">IO formatted JSON</a>
</li>
<li>
<a href="#non-io-formatted-json" class="toc-h2 toc-link" data-title="Non-IO formatted JSON">Non-IO formatted JSON</a>
</li>
<li>
<a href="#that-39-s-not-json-at-all" class="toc-h2 toc-link" data-title="That's not JSON at all!">That's not JSON at all!</a>
</li>
</ul>
</li>
<li class="on-screen">
<a href="#webhook-receivers" class="toc-h1 toc-link" data-title="Webhook Receivers">
Webhook Receivers
<span class="menu-arrow">
<svg width="18" height="18" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1171 960q0 13-10 23l-466 466q-10 10-23 10t-23-10l-50-50q-10-10-10-23t10-23l393-393-393-393q-10-10-10-23t10-23l50-50q10-10 23-10t23 10l466 466q10 10 10 23z"/></svg>
<!-- <span>&gt;</span> -->
</span>
</a>
<ul class="toc-list-h2">
<li>
<a href="#raw-webhooks" class="toc-h2 toc-link" data-title="Raw Webhooks">Raw Webhooks</a>
</li>
<li>
<a href="#notify-webhooks" class="toc-h2 toc-link" data-title="Notify Webhooks">Notify Webhooks</a>
</li>
</ul>
</li>
<li class="on-screen">
<a href="#securing-your-io-account" class="toc-h1 toc-link" data-title="Securing your IO Account">
Securing your IO Account
<span class="menu-arrow">
<svg width="18" height="18" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1171 960q0 13-10 23l-466 466q-10 10-23 10t-23-10l-50-50q-10-10-10-23t10-23l393-393-393-393q-10-10-10-23t10-23l50-50q10-10 23-10t23 10l466 466q10 10 10 23z"/></svg>
<!-- <span>&gt;</span> -->
</span>
</a>
<ul class="toc-list-h2">
<li>
<a href="#i-accidentially-shared-my-key-what-do-i-do-now" class="toc-h2 toc-link" data-title="I accidentially shared my key, what do I do now?">I accidentially shared my key, what do I do now?</a>
</li>
</ul>
</li>
</ul>
<ul class="toc-footer">
<li><a href='https://io.adafruit.com'>Adafruit IO</a></li>
<li><a href='https://io.adafruit.com/blog'>Adafruit IO News</a></li>
<li><a href='https://io.adafruit.com/plus'>Adafruit IO Plus</a></li>
<li><a href='https://io.adafruit.com/terms'>Adafruit IO ToS</a></li>
<li><a href='https://io.adafruit.com/feedback'>Submit Feedback</a></li>
</ul>
</div>
<div class="page-wrapper">
<div class="dark-box"></div>
<div class="content">
<h1 id='adafruit-io-api-cookbook'>Adafruit IO API Cookbook</h1>
<p>This page contains a number of recipes related to Adafruit IO which have been found useful in the past. You can add and contribute to this file by filing an <code>issue</code> on the GitHub repository, or by editing this file and submitting a pull request.</p>
<h1 id='feed-identifiers'>Feed Identifiers</h1>
<p>Names are for humans.</p>
<p>Keys are for computers.</p>
<p>You tell the computer the name, and it will tell you the key.</p>
<p>When using Adafruit IO, you&#39;ll want to tell the client (the computer) the feed&#39;s <strong>key</strong> instead of the feed&#39;s <strong>name</strong>.</p>
<p>For more information about this topic:, visit <a href="https://learn.adafruit.com/naming-things-in-adafruit-io/introduction">the learn guide for feeds</a> or the <a href="https://io.adafruit.com/blog/tips/2016/07/14/naming-feeds">IO Development blog post about naming feeds</a>.</p>
<h1 id='formatting-values'>Formatting values</h1>
<p>Adafruit IO stores all data as UTF-8 strings without applying formatting. <em>Some</em> data is formatted when rendered on dashboards, but you should always be able to get back what you sent.</p>
<h2 id='floating-point-data'>Floating Point Data</h2>
<p>If you&#39;re <em>sending</em> <code>3.1415</code> but you only want to <em>see</em> <code>3.14</code> - reduce the value to the desired amount of precision in your code. You can round (up or down) or truncate this value to get it in the format you want Adafruit IO to display.</p>
<h1 id='image-data'>Image Data</h1>
<p>Using an <em>Image Block</em> on an Adafruit IO, you can automatically display a Base64 image data string on your dashboard by sending a Base64 image data string to an Adafruit IO feed. By dragging and dropping an image onto the block in your browser, you can also send image data on the same feed.</p>
<h2 id='design-considerations'>Design Considerations</h2>
<p>There are some important things to keep in mind when using this feature. Normal feeds are limited to 1KB of data, or about 1024 bytes, for publishing. Turning off feed history from the feed settings page allows publishing up to 100KB, or 102400 bytes, of data.</p>
<p>When using the drag-and-drop feature of Adafruit IO dashboards or feed pages, image conversion from binary to Base64 happens inside the browser. That means no image pre-compression or optimization and additional size boost due to the conversion from binary to Base64.</p>
<p>Youll have to do your own testing to figure out what an appropriate image size and format (png, gif, or bmp) for you are. For example, <a href="https://io.adafruit.com/blog/images/2016-12-14-power-switch.png">the .png image used for testing</a> below has an on disk size of 68089 bytes, but a Base64 value of 90788 bytes, an expansion factor of about 150%, which is really close to the limit.</p>
<p><img src="https://io.adafruit.com/blog/images/2018-08-10-image-upload-size.png" alt="base64imagepreview" /></p>
<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="" /></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>
<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="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>
<p>The two most important factors for published image data size are image resolution and image formatting. The <a href="https://pypi.org/project/Pillow/">Python Imaging Library</a> (<code>pillow</code>) allows us to resize images and has built in support for jpeg optimization.</p>
<p>The key chunk of code is here:</p>
<div class="center-column"></div>
<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)
camera.capture(stream, format='jpeg', resize=(800, 600))
stream.seek(0)
# use Python Imaging Library to optimize the final image data
image = Image.open(stream, 'r')
optim_stream = io.BytesIO()
image.save(optim_stream, format='jpeg', quality=70, optimize=True)
optim_stream.seek(0)
# convert image binary data to base64 string
value = base64.b64encode(optim_stream.read())
if len(value) &gt; 102400:
print("image file too big!")
return
client.publish('image-stream', value)
</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>
<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></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><div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="c1">// A basic data record</span>
<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></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>
<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>
<h2 id='double-encoded-json-strings'>Double encoded JSON strings</h2>
<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>
<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></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><strong>Important Note:</strong> Data saved in this manner (multiple records saved as JSON in a single feed) will make the data unusable by the IO dashboard and other features such as actions. IO needs a single value saved into a feed in order to use it in this manner. Saving the JSON objects into a feed is a useful feature if you only need to use the data between two devices, for example.</p>
<div class="center-column"></div>
<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></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></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><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></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>
<h2 id='that-39-s-not-json-at-all'>That&#39;s not JSON at all!</h2>
<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>
<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="dl">"</span><span class="s2">eyJzb21ldGhpbmciOiJoZXJlIn0=</span><span class="dl">"</span><span class="p">)</span>
<span class="c1">// {"something":"here"}</span>
</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 (although we do display base64 encoded images), 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>
<p>You can access a webhook by navigating to your feed and clicking the <em>Webhooks</em> button on the right-hand sidebar.</p>
<h2 id='raw-webhooks'>Raw Webhooks</h2>
<p>If you want to receive the whole contents of webhook events--for example, when receiving webhook notifications from a service like Slack or GitHub where you don&#39;t have control over the payload the service is sending--add <code>/raw</code> to the end of the Adafruit IO webhook URL that you share with the service.</p>
<h2 id='notify-webhooks'>Notify Webhooks</h2>
<p>If you only want to be notified that an event has happened, rather than have to handle all the data from an event--for example, if a service like GitHub is trying to send 7KB of JSON to your ESP8266--add <code>/notify</code> to the end of your Adafruit IO webhook URL. When data arrives, your feed will receive the message &quot;ping&quot;.</p>
<h1 id='securing-your-io-account'>Securing your IO Account</h1>
<p>Your IO Account includes a secret API key. This key is private and should not be shared with anyone.</p>
<p>But, a common pitfalls of the key is it may be accidentally shared by posted code on GitHub or social media. If anyone gains access to your key, <strong>they will have access to your Adafruit IO account</strong>.</p>
<h2 id='i-accidentially-shared-my-key-what-do-i-do-now'>I accidentially shared my key, what do I do now?</h2>
<p>You&#39;ll need to generate a new key. This process is simple, but not reversable. Once you generate a new key for your Adafruit IO account,
all devices using the previous Adafruit IO key will need to be updated to the new key.</p>
<p>To rengenerate your Adafruit IO Key:
* Navigate to io.adafruit.com and log into your account.
* Click the key icon on the header.
* Click the &quot;Regenerate Key&quot; button and confirm the action.
* The value of &quot;Active Key&quot; will change to a new key. Replace all instances of the previous key with the new one.</p>
</div>
<div class="dark-box">
<div class="lang-selector">
<a href="#" data-language-name="shell">CURL</a>
<a href="#" data-language-name="cpp">Arduino</a>
<a href="#" data-language-name="python">Python</a>
<a href="#" data-language-name="python">Circuitpython</a>
<a href="#" data-language-name="ruby">Ruby</a>
</div>
</div>
</div>
</body>
</html>

215
deploy.sh
View file

@ -1,215 +0,0 @@
#!/usr/bin/env bash
set -o errexit #abort if any command fails
me=$(basename "$0")
help_message="\
Usage: $me [-c FILE] [<options>]
Deploy generated files to a git branch.
Options:
-h, --help Show this help information.
-v, --verbose Increase verbosity. Useful for debugging.
-e, --allow-empty Allow deployment of an empty directory.
-m, --message MESSAGE Specify the message used when committing on the
deploy branch.
-n, --no-hash Don't append the source commit's hash to the deploy
commit's message.
--source-only Only build but not push
--push-only Only push but not build
"
run_build() {
bundle exec middleman build --clean
}
parse_args() {
# Set args from a local environment file.
if [ -e ".env" ]; then
source .env
fi
# Parse arg flags
# If something is exposed as an environment variable, set/overwrite it
# here. Otherwise, set/overwrite the internal variable instead.
while : ; do
if [[ $1 = "-h" || $1 = "--help" ]]; then
echo "$help_message"
return 0
elif [[ $1 = "-v" || $1 = "--verbose" ]]; then
verbose=true
shift
elif [[ $1 = "-e" || $1 = "--allow-empty" ]]; then
allow_empty=true
shift
elif [[ ( $1 = "-m" || $1 = "--message" ) && -n $2 ]]; then
commit_message=$2
shift 2
elif [[ $1 = "-n" || $1 = "--no-hash" ]]; then
GIT_DEPLOY_APPEND_HASH=false
shift
else
break
fi
done
# Set internal option vars from the environment and arg flags. All internal
# vars should be declared here, with sane defaults if applicable.
# Source directory & target branch.
deploy_directory=build
deploy_branch=gh-pages
#if no user identity is already set in the current git environment, use this:
default_username=${GIT_DEPLOY_USERNAME:-deploy.sh}
default_email=${GIT_DEPLOY_EMAIL:-}
#repository to deploy to. must be readable and writable.
repo=origin
#append commit hash to the end of message by default
append_hash=${GIT_DEPLOY_APPEND_HASH:-true}
}
main() {
parse_args "$@"
enable_expanded_output
if ! git diff --exit-code --quiet --cached; then
echo Aborting due to uncommitted changes in the index >&2
return 1
fi
commit_title=`git log -n 1 --format="%s" HEAD`
commit_hash=` git log -n 1 --format="%H" HEAD`
#default commit message uses last title if a custom one is not supplied
if [[ -z $commit_message ]]; then
commit_message="publish: $commit_title"
fi
#append hash to commit message unless no hash flag was found
if [ $append_hash = true ]; then
commit_message="$commit_message"$'\n\n'"generated from commit $commit_hash"
fi
previous_branch=`git rev-parse --abbrev-ref HEAD`
if [ ! -d "$deploy_directory" ]; then
echo "Deploy directory '$deploy_directory' does not exist. Aborting." >&2
return 1
fi
# must use short form of flag in ls for compatibility with macOS and BSD
if [[ -z `ls -A "$deploy_directory" 2> /dev/null` && -z $allow_empty ]]; then
echo "Deploy directory '$deploy_directory' is empty. Aborting. If you're sure you want to deploy an empty tree, use the --allow-empty / -e flag." >&2
return 1
fi
if git ls-remote --exit-code $repo "refs/heads/$deploy_branch" ; then
# deploy_branch exists in $repo; make sure we have the latest version
disable_expanded_output
git fetch --force $repo $deploy_branch:$deploy_branch
enable_expanded_output
fi
# check if deploy_branch exists locally
if git show-ref --verify --quiet "refs/heads/$deploy_branch"
then incremental_deploy
else initial_deploy
fi
restore_head
}
initial_deploy() {
git --work-tree "$deploy_directory" checkout --orphan $deploy_branch
git --work-tree "$deploy_directory" add --all
commit+push
}
incremental_deploy() {
#make deploy_branch the current branch
git symbolic-ref HEAD refs/heads/$deploy_branch
#put the previously committed contents of deploy_branch into the index
git --work-tree "$deploy_directory" reset --mixed --quiet
git --work-tree "$deploy_directory" add --all
set +o errexit
diff=$(git --work-tree "$deploy_directory" diff --exit-code --quiet HEAD --)$?
set -o errexit
case $diff in
0) echo No changes to files in $deploy_directory. Skipping commit.;;
1) commit+push;;
*)
echo git diff exited with code $diff. Aborting. Staying on branch $deploy_branch so you can debug. To switch back to master, use: git symbolic-ref HEAD refs/heads/master && git reset --mixed >&2
return $diff
;;
esac
}
commit+push() {
set_user_id
git --work-tree "$deploy_directory" commit -m "$commit_message"
disable_expanded_output
#--quiet is important here to avoid outputting the repo URL, which may contain a secret token
git push --quiet $repo $deploy_branch
enable_expanded_output
}
#echo expanded commands as they are executed (for debugging)
enable_expanded_output() {
if [ $verbose ]; then
set -o xtrace
set +o verbose
fi
}
#this is used to avoid outputting the repo URL, which may contain a secret token
disable_expanded_output() {
if [ $verbose ]; then
set +o xtrace
set -o verbose
fi
}
set_user_id() {
if [[ -z `git config user.name` ]]; then
git config user.name "$default_username"
fi
if [[ -z `git config user.email` ]]; then
git config user.email "$default_email"
fi
}
restore_head() {
if [[ $previous_branch = "HEAD" ]]; then
#we weren't on any branch before, so just set HEAD back to the commit it was on
git update-ref --no-deref HEAD $commit_hash $deploy_branch
else
git symbolic-ref HEAD refs/heads/$previous_branch
fi
git reset --mixed
}
filter() {
sed -e "s|$repo|\$repo|g"
}
sanitize() {
"$@" 2> >(filter 1>&2) | filter
}
if [[ $1 = --source-only ]]; then
run_build
elif [[ $1 = --push-only ]]; then
main "$@"
else
run_build
main "$@"
fi

View file

@ -1,7 +0,0 @@
services:
app:
build: .
ports:
- 4567:4567
volumes:
- .:/usr/src/app

View file

@ -1,148 +0,0 @@
{
"IcoMoonType": "selection",
"icons": [
{
"icon": {
"paths": [
"M438.857 73.143q119.429 0 220.286 58.857t159.714 159.714 58.857 220.286-58.857 220.286-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286 58.857-220.286 159.714-159.714 220.286-58.857zM512 785.714v-108.571q0-8-5.143-13.429t-12.571-5.429h-109.714q-7.429 0-13.143 5.714t-5.714 13.143v108.571q0 7.429 5.714 13.143t13.143 5.714h109.714q7.429 0 12.571-5.429t5.143-13.429zM510.857 589.143l10.286-354.857q0-6.857-5.714-10.286-5.714-4.571-13.714-4.571h-125.714q-8 0-13.714 4.571-5.714 3.429-5.714 10.286l9.714 354.857q0 5.714 5.714 10t13.714 4.286h105.714q8 0 13.429-4.286t6-10z"
],
"attrs": [],
"isMulticolor": false,
"tags": [
"exclamation-circle"
],
"defaultCode": 61546,
"grid": 14
},
"attrs": [],
"properties": {
"id": 100,
"order": 4,
"prevSize": 28,
"code": 58880,
"name": "exclamation-sign",
"ligatures": ""
},
"setIdx": 0,
"iconIdx": 0
},
{
"icon": {
"paths": [
"M585.143 786.286v-91.429q0-8-5.143-13.143t-13.143-5.143h-54.857v-292.571q0-8-5.143-13.143t-13.143-5.143h-182.857q-8 0-13.143 5.143t-5.143 13.143v91.429q0 8 5.143 13.143t13.143 5.143h54.857v182.857h-54.857q-8 0-13.143 5.143t-5.143 13.143v91.429q0 8 5.143 13.143t13.143 5.143h256q8 0 13.143-5.143t5.143-13.143zM512 274.286v-91.429q0-8-5.143-13.143t-13.143-5.143h-109.714q-8 0-13.143 5.143t-5.143 13.143v91.429q0 8 5.143 13.143t13.143 5.143h109.714q8 0 13.143-5.143t5.143-13.143zM877.714 512q0 119.429-58.857 220.286t-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286 58.857-220.286 159.714-159.714 220.286-58.857 220.286 58.857 159.714 159.714 58.857 220.286z"
],
"attrs": [],
"isMulticolor": false,
"tags": [
"info-circle"
],
"defaultCode": 61530,
"grid": 14
},
"attrs": [],
"properties": {
"id": 85,
"order": 3,
"name": "info-sign",
"prevSize": 28,
"code": 58882
},
"setIdx": 0,
"iconIdx": 2
},
{
"icon": {
"paths": [
"M733.714 419.429q0-16-10.286-26.286l-52-51.429q-10.857-10.857-25.714-10.857t-25.714 10.857l-233.143 232.571-129.143-129.143q-10.857-10.857-25.714-10.857t-25.714 10.857l-52 51.429q-10.286 10.286-10.286 26.286 0 15.429 10.286 25.714l206.857 206.857q10.857 10.857 25.714 10.857 15.429 0 26.286-10.857l310.286-310.286q10.286-10.286 10.286-25.714zM877.714 512q0 119.429-58.857 220.286t-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286 58.857-220.286 159.714-159.714 220.286-58.857 220.286 58.857 159.714 159.714 58.857 220.286z"
],
"attrs": [],
"isMulticolor": false,
"tags": [
"check-circle"
],
"defaultCode": 61528,
"grid": 14
},
"attrs": [],
"properties": {
"id": 83,
"order": 9,
"prevSize": 28,
"code": 58886,
"name": "ok-sign"
},
"setIdx": 0,
"iconIdx": 6
},
{
"icon": {
"paths": [
"M658.286 475.429q0-105.714-75.143-180.857t-180.857-75.143-180.857 75.143-75.143 180.857 75.143 180.857 180.857 75.143 180.857-75.143 75.143-180.857zM950.857 950.857q0 29.714-21.714 51.429t-51.429 21.714q-30.857 0-51.429-21.714l-196-195.429q-102.286 70.857-228 70.857-81.714 0-156.286-31.714t-128.571-85.714-85.714-128.571-31.714-156.286 31.714-156.286 85.714-128.571 128.571-85.714 156.286-31.714 156.286 31.714 128.571 85.714 85.714 128.571 31.714 156.286q0 125.714-70.857 228l196 196q21.143 21.143 21.143 51.429z"
],
"width": 951,
"attrs": [],
"isMulticolor": false,
"tags": [
"search"
],
"defaultCode": 61442,
"grid": 14
},
"attrs": [],
"properties": {
"id": 2,
"order": 1,
"prevSize": 28,
"code": 58887,
"name": "icon-search"
},
"setIdx": 0,
"iconIdx": 7
}
],
"height": 1024,
"metadata": {
"name": "slate",
"license": "SIL OFL 1.1"
},
"preferences": {
"showGlyphs": true,
"showQuickUse": true,
"showQuickUse2": true,
"showSVGs": true,
"fontPref": {
"prefix": "icon-",
"metadata": {
"fontFamily": "slate",
"majorVersion": 1,
"minorVersion": 0,
"description": "Based on FontAwesome",
"license": "SIL OFL 1.1"
},
"metrics": {
"emSize": 1024,
"baseline": 6.25,
"whitespace": 50
},
"resetPoint": 58880,
"showSelector": false,
"selector": "class",
"classSelector": ".icon",
"showMetrics": false,
"showMetadata": true,
"showVersion": true,
"ie7": false
},
"imagePref": {
"prefix": "icon-",
"png": true,
"useClassSelector": true,
"color": 4473924,
"bgColor": 16777215
},
"historySize": 100,
"showCodes": true,
"gridSize": 16,
"showLiga": false
}
}

View file

Before

Width:  |  Height:  |  Size: 434 KiB

After

Width:  |  Height:  |  Size: 434 KiB

View file

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View file

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View file

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View file

Before

Width:  |  Height:  |  Size: 703 B

After

Width:  |  Height:  |  Size: 703 B

View file

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View file

Before

Width:  |  Height:  |  Size: 257 B

After

Width:  |  Height:  |  Size: 257 B

View file

Before

Width:  |  Height:  |  Size: 773 B

After

Width:  |  Height:  |  Size: 773 B

View file

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View file

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View file

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View file

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

View file

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View file

Before

Width:  |  Height:  |  Size: 96 B

After

Width:  |  Height:  |  Size: 96 B

5289
index.html Normal file

File diff suppressed because it is too large Load diff

131
javascripts/all.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,3 +0,0 @@
def error_message(message)
"<p class='error-message-sample'>#{message}</p>"
end

View file

@ -1,16 +0,0 @@
module Multilang
def block_code(code, full_lang_name)
if full_lang_name
parts = full_lang_name.split('--')
rouge_lang_name = (parts) ? parts[0] : "" # just parts[0] here causes null ref exception when no language specified
super(code, rouge_lang_name).sub("highlight #{rouge_lang_name}") do |match|
match + " tab-" + full_lang_name
end
else
super(code, full_lang_name)
end
end
end
require 'middleman-core/renderers/redcarpet'
Middleman::Renderers::MiddlemanRedcarpetHTML.send :include, Multilang

View file

@ -1,22 +0,0 @@
# Nested unique header generation
require 'middleman-core/renderers/redcarpet'
class NestingUniqueHeadCounter < Middleman::Renderers::MiddlemanRedcarpetHTML
def initialize
super
@@headers_history = {} if !defined?(@@headers_history)
end
def header(text, header_level)
friendly_text = text.gsub(/<[^>]*>/,"").parameterize
@@headers_history[header_level] = text.parameterize
if header_level > 1
for i in (header_level - 1).downto(1)
friendly_text.prepend("#{@@headers_history[i]}-") if @@headers_history.key?(i)
end
end
return "<h#{header_level} id='#{friendly_text}'>#{text}</h#{header_level}>"
end
end

View file

@ -1,31 +0,0 @@
require 'nokogiri'
def toc_data(page_content)
html_doc = Nokogiri::HTML::DocumentFragment.parse(page_content)
# get a flat list of headers
headers = []
html_doc.css('h1, h2, h3').each do |header|
headers.push({
id: header.attribute('id').to_s,
content: header.children,
title: header.children.to_s.gsub(/<[^>]*>/, ''),
level: header.name[1].to_i,
children: []
})
end
[3,2].each do |header_level|
header_to_nest = nil
headers = headers.reject do |header|
if header[:level] == header_level
header_to_nest[:children].push header if header_to_nest
true
else
header_to_nest = header if header[:level] < header_level
false
end
end
end
headers
end

View file

@ -1,25 +0,0 @@
# Unique header generation
require 'middleman-core/renderers/redcarpet'
require 'digest'
class UniqueHeadCounter < Middleman::Renderers::MiddlemanRedcarpetHTML
def initialize
super
@head_count = {}
end
def header(text, header_level)
friendly_text = text.gsub(/<[^>]*>/,"").parameterize
if friendly_text.strip.length == 0
# Looks like parameterize removed the whole thing! It removes many unicode
# characters like Chinese and Russian. To get a unique URL, let's just
# URI escape the whole header
friendly_text = Digest::SHA1.hexdigest(text)[0,10]
end
@head_count[friendly_text] ||= 0
@head_count[friendly_text] += 1
if @head_count[friendly_text] > 1
friendly_text += "-#{@head_count[friendly_text]}"
end
return "<h#{header_level} id='#{friendly_text}'>#{text}</h#{header_level}>"
end
end

1011
mqtt.html Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,36 +0,0 @@
---
title: Adafruit IO API Cookbook
language_tabs:
- shell: CURL
- cpp: Arduino
- python: Python
- python: Circuitpython
- ruby: Ruby
toc_prepend:
- href: ./
text: Adafruit IO HTTP API
- href: mqtt
text: Adafruit IO MQTT API
toc_footers:
- <a href='https://io.adafruit.com'>Adafruit IO</a>
- <a href='https://io.adafruit.com/blog'>Adafruit IO News</a>
- <a href='https://io.adafruit.com/plus'>Adafruit IO Plus</a>
- <a href='https://io.adafruit.com/terms'>Adafruit IO ToS</a>
- <a href='https://io.adafruit.com/feedback'>Submit Feedback</a>
includes:
- cookbook.md.erb
- cookbook/feed_identifiers.md.erb
- cookbook/formatting_values.md.erb
- cookbook/images.md.erb
- cookbook/sending_json.md.erb
- cookbook/webhook_receivers.md.erb
- cookbook/securing_io_account.md.erb
search: true
---

View file

@ -1,2 +0,0 @@
<div class="center-column"></div>
<%= yield %>

View file

@ -1,38 +0,0 @@
# Authentication
Your Adafruit IO Key is used to restrict or grant access to your data. The key is unique and covers every use of the Adafruit IO API for your account. You can access your key on any IO page by clicking on the golden key icon:
<%= image_tag "images/authentication/aio-key-dashboard-link.png" %>
Or by clicking on the "View Adafruit IO Key" link in the small screen drop-down menu while you're visiting Adafruit IO.
<%= image_tag "images/authentication/aio-key-sidebar-link.png" %>
Now you can copy the key directly from the information form that pops up, or copy one of the code samples that includes your key and username together.
<%= image_tag "images/authentication/aio-key-modal.png" %>
## Including an Adafruit IO Key
```shell
curl -H "X-AIO-Key: b780002b85d6411ca0ad9f9c60195f72" \
https://io.adafruit.com/api/v2/test_username/feeds
# or
curl "https://io.adafruit.com/api/v2/test_username/feeds?x-aio-key=b780002b85d6411ca0ad9f9c60195f72"
```
```ruby
require 'adafruit/io'
username = "test_username"
api_key = "b780002b85d6411ca0ad9f9c60195f72"
api = Adafruit::IO::Client.new key: api_key, username: username
```
When making HTTP requests to Adafruit IO, you can include the API key as a query parameter named `x-aio-key` or as a request header named `X-AIO-Key`. In both cases, "X-AIO-Key" is case insensitive.
**NOTE**: if you regenerate your AIO key, your old key will be immediately invalidated, so you'll have to replace it in any scripts or sketches where it is in use.
**NOTE**: it is a best practice to avoid including your API key in the URL as a query parameter. Some situations may require this, but try to avoid it if you can.

View file

@ -1,18 +0,0 @@
# Client Libraries
We have lots of client libraries to help you get started with your project:
* [Arduino C++](https://github.com/adafruit/Adafruit_IO_Arduino)
* [CircuitPython](https://github.com/adafruit/Adafruit_CircuitPython_AdafruitIO/)
* [Python](https://github.com/adafruit/Adafruit_IO_Python)
* [Ruby](https://github.com/adafruit/io-client-ruby)
**Note:** The following two libraries use V1 of the Adafruit API which have been [deprecated](https://io.adafruit.com/api/docs/).
* [Node.js](https://github.com/adafruit/adafruit-io-node-client)
* [Go](https://github.com/adafruit/io-client-go)
They're all open source, so if they don't already do what you want, you can fork them and add any feature you'd like.

View file

@ -1,5 +0,0 @@
# Adafruit IO API Cookbook
This page contains a number of recipes related to Adafruit IO which have been found useful in the past. You can add and contribute to this file by filing an `issue` on the GitHub repository, or by editing this file and submitting a pull request.

View file

@ -1,15 +0,0 @@
# Errors
The Adafruit IO API uses the following error codes:
Error Code | Meaning
---------- | -------
400 | Bad Request -- Your request is invalid or was in the wrong format.
401 | Unauthorized -- Your API key is wrong or you're trying to view a resource you don't own.
403 | Forbidden -- This action is not permitted.
404 | Not Found -- The specified record could not be found.
406 | Not Acceptable -- You requested a format that we don't serve.
422 | Unprocessable Entity -- You've sent data we can't accept/understand. Is the value field (string/number) missing?
429 | Too Many Requests -- You're sending or requesting data too quickly! Slow down!
500 | Internal Server Error -- We had a problem with our server. Try again later.
503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later.

View file

@ -1,11 +0,0 @@
# Adafruit IO HTTP API
The Adafruit IO HTTP API provides access to your Adafruit IO data from any programming language or hardware environment that can speak HTTP. The easiest way to get started is with an [Adafruit Learning Guide](https://learn.adafruit.com/series/adafruit-io-basics) and a simple Internet of Things capable device like the [Feather Huzzah](https://www.adafruit.com/product/2821) or a more complicated one like the [PyPortal](https://www.adafruit.com/product/4116).
## About the API Docs
This API documentation is hosted on GitHub Pages and is available [on GitHub](https://github.com/adafruit/Adafruit_IO_Documentation).
**Spotted something incorrect or broken?** [Click here to file an issue on the repository](https://github.com/adafruit/Adafruit_IO_Documentation/issues/new)
For questions or comments [visit the Adafruit IO Feedback page](https://io.adafruit.com/feedback) or the [#help-with-adafruit-io channel on the Adafruit Discord server](https://discord.gg/adafruit).

View file

@ -1,15 +0,0 @@
# Rate Limiting
Adafruit IO imposes a rate limit on all data modification APIs to prevent excessive load on the service. If a user performs too many data create, update, or delete actions in a short period of time then the system will start rejecting requests.
If you have a free Adafruit IO Account, the rate limit is **30 data points per minute**.
If you have [upgraded to an Adafruit IO Plus account](https://io.adafruit.com/plus), the base rate limit is **60 data points per minute**.
***If you exceed this limit***, a notice will be sent to the `{username}/throttle` MQTT topic. You can subscribe to the topic if you wish to know when the Adafruit IO rate limit has been exceeded for your user account. This limit applies to all **Data record modification** actions over the HTTP and MQTT APIs, so if you have multiple devices or clients publishing data, be sure to delay their updates enough that the total rate is below your account limit.
**One data record modification** is any action that creates, updates, or deletes a single Data record.
**A best practice is to only save or modify data within the hot part of your code loop.** You want to handle authentication and any other API requests (creating/getting feeds, etc) before you start your main code loop where you save data.
We have general API throttles to ensure the API isn't being improperly used either by accident or for nefarious purposes. This throttle level is higher than any data rate limit throttles, but you may run into it if your code isn't optimized. One example would be if in the main loop of your code you are not only sending data, but also authenticating, retrieving all feeds, or anything else that doesn't involve saving or modifying data to a feed. In that scenario, you would be hitting the API 3x more times than necessary, and could get throttled, even if you're saving data within your allotted rate limit.

View file

@ -1,12 +0,0 @@
# Feed Identifiers
Names are for humans.
Keys are for computers.
You tell the computer the name, and it will tell you the key.
When using Adafruit IO, you'll want to tell the client (the computer) the feed's **key** instead of the feed's **name**.
For more information about this topic:, visit [the learn guide for feeds](https://learn.adafruit.com/naming-things-in-adafruit-io/introduction) or the [IO Development blog post about naming feeds](https://io.adafruit.com/blog/tips/2016/07/14/naming-feeds).

View file

@ -1,9 +0,0 @@
# Formatting values
Adafruit IO stores all data as UTF-8 strings without applying formatting. _Some_ data is formatted when rendered on dashboards, but you should always be able to get back what you sent.
## Floating Point Data
If you're _sending_ `3.1415` but you only want to _see_ `3.14` - reduce the value to the desired amount of precision in your code. You can round (up or down) or truncate this value to get it in the format you want Adafruit IO to display.

View file

@ -1,83 +0,0 @@
# Image Data
Using an *Image Block* on an Adafruit IO, you can automatically display a Base64 image data string on your dashboard by sending a Base64 image data string to an Adafruit IO feed. By dragging and dropping an image onto the block in your browser, you can also send image data on the same feed.
## Design Considerations
There are some important things to keep in mind when using this feature. Normal feeds are limited to 1KB of data, or about 1024 bytes, for publishing. Turning off feed history from the feed settings page allows publishing up to 100KB, or 102400 bytes, of data.
When using the drag-and-drop feature of Adafruit IO dashboards or feed pages, image conversion from binary to Base64 happens inside the browser. That means no image pre-compression or optimization and additional size boost due to the conversion from binary to Base64.
Youll have to do your own testing to figure out what an appropriate image size and format (png, gif, or bmp) for you are. For example, [the .png image used for testing](https://io.adafruit.com/blog/images/2016-12-14-power-switch.png) below has an on disk size of 68089 bytes, but a Base64 value of 90788 bytes, an expansion factor of about 150%, which is really close to the limit.
![base64imagepreview](https://io.adafruit.com/blog/images/2018-08-10-image-upload-size.png)
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 [ImageOptim](https://imageoptim.com/versions) tool. The base size on disk is 10665 bytes and the Base64 encoded size is 14221 bytes.
<%= image_tag "images/cookbook/plain-text-on-a-plain-background.png" %>
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.
```sh
# on macOS 10.14 with ImageMagick 6.9.9-37
$ convert small-image-with-text.gif -colors 3 \
-strip -coalesce -layers Optimize \
small-image-with-text-optim.gif
$ base64 -i small-image-with-text-optim.gif \
-o small-image-with-text-optim.gif.base64
```
<%= image_tag "images/cookbook/small-image-with-text-optim.gif" %>
## Publishing Image Data
[Here's an example Python sketch](https://gist.github.com/abachman/b0d3687227da7f82818174a89b325588) that publishes image data to an Adafruit IO feed when a signal is received on another IO feed.
The two most important factors for published image data size are image resolution and image formatting. The [Python Imaging Library](https://pypi.org/project/Pillow/) (`pillow`) allows us to resize images and has built in support for jpeg optimization.
The key chunk of code is here:
<% partial 'helpers/inline_code' do %>
```
# create an in-memory file to store raw image data
stream = io.BytesIO()
# write camera data to the stream (file)
camera.capture(stream, format='jpeg', resize=(800, 600))
stream.seek(0)
# use Python Imaging Library to optimize the final image data
image = Image.open(stream, 'r')
optim_stream = io.BytesIO()
image.save(optim_stream, format='jpeg', quality=70, optimize=True)
optim_stream.seek(0)
# convert image binary data to base64 string
value = base64.b64encode(optim_stream.read())
if len(value) > 102400:
print("image file too big!")
return
client.publish('image-stream', value)
```
<% end %>
We create an image, optimize it, convert it to a Base64 string, and then immediately publish that string to Adafruit IO. It'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.
If you wanted to do the same from a single command line command, given an existing image file, you could use curl's support for uploading files from stdin:
<% partial 'helpers/inline_code' do %>
```
$ base64 image.jpg | curl -F value=@- -H "X-AIO-Key: {io_key}" \
https://io.adafruit.com/api/v2/{username}/feeds/{feed_key}/data
```
<% end %>
The `-F value=@-` tells curl, "I want to POST a multipart form with a single parameter named 'value' whose value is the input to this command." The preceding `base64` command and the `|` character mean that the input to the curl command is the base64 string version of the binary image data.
Stop by the forums if this leaves you with questions or if you're looking for examples in your favorite programming language :D

View file

@ -1,17 +0,0 @@
# Securing your IO Account
Your IO Account includes a secret API key. This key is private and should not be shared with anyone.
But, a common pitfalls of the key is it may be accidentally shared by posted code on GitHub or social media. If anyone gains access to your key, **they will have access to your Adafruit IO account**.
## I accidentially shared my key, what do I do now?
You'll need to generate a new key. This process is simple, but not reversable. Once you generate a new key for your Adafruit IO account,
all devices using the previous Adafruit IO key will need to be updated to the new key.
To rengenerate your Adafruit IO Key:
* Navigate to io.adafruit.com and log into your account.
* Click the key icon on the header.
* Click the "Regenerate Key" button and confirm the action.
* The value of "Active Key" will change to a new key. Replace all instances of the previous key with the new one.

View file

@ -1,91 +0,0 @@
# Sending and Storing JSON
```javascript
// A basic data record
{
"value": 22.587,
"lat": 38.1123,
"lon": -91.2325,
"ele": 112
}
```
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 [HTTP create data API description](/#create-data).
This lets us store the individual value, `22.587`, and data about the value: its latitude, longitude, and elevation. Data about the data is "metadata"!
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.
## Double encoded JSON strings
**The safest way to can send JSON data as a value** is to "double encode" it before sending, in which case IO will treat it as a raw string. If you're using something like javascript's `JSON.stringify` function or Ruby's `JSON.generate`, double encoding means passing the result of `JSON.stringify` through `JSON.stringify` a second time.
<% partial 'helpers/inline_code' do %>
```javascript
JSON.stringify({
"value": JSON.stringify({"sensor-1":22.587,"sensor-2":13.182})
})
```
<% end %>
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.
**Important Note:** Data saved in this manner (multiple records saved as JSON in a single feed) will make the data unusable by the IO dashboard and other features such as actions. IO needs a single value saved into a feed in order to use it in this manner. Saving the JSON objects into a feed is a useful feature if you only need to use the data between two devices, for example.
<% partial 'helpers/inline_code' do %>
```javascript
var data = JSON.parse(message)
var value = JSON.parse(data.value)
```
<% end %>
## IO formatted JSON
```javascript
{
"value": {"sensor-1":22.587,"sensor-2":13.182},
"lat": 38.1123,
"lon": -91.2325,
"ele": 112
}
```
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, {"sensor-1":22.587,"sensor-2":13.182}, the "wrapped" version would look like the value on the right.
It'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.
## Non-IO formatted JSON
```
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
```
Another way you can send raw JSON data is to just send it. If Adafruit IO doesn't find a "value" 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 `{"sensor-1":22.587,"sensor-2":13.182}` will result in `{"sensor-1":22.587,"sensor-2":13.182}` being stored in IO and sent to MQTT subscribers.
**NOTE:** This solution is the riskiest, because if your JSON blob includes the key named `value`, then IO will interpret _that_ as the value you want to store and ignore all the other keys.
## That's not JSON at all!
If you want to be absolutely sure that Adafruit IO will not interfere with the data you're sending, encode it as a [Base64](https://en.wikipedia.org/wiki/Base64) string first.
<% partial 'helpers/inline_code' do %>
```javascript
btoa(JSON.stringify({ "something": "here" }))
// "eyJzb21ldGhpbmciOiJoZXJlIn0="
atob("eyJzb21ldGhpbmciOiJoZXJlIn0=")
// {"something":"here"}
```
<% end %>
This solution is also ideal if you want to store or send binary data with Adafruit IO. You won't get to see any pretty charts (although we do display base64 encoded images), but your data will remain exactly the way you left it.

View file

@ -1,13 +0,0 @@
# Webhook Receivers
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.
You can access a webhook by navigating to your feed and clicking the _Webhooks_ button on the right-hand sidebar.
## Raw Webhooks
If you want to receive the whole contents of webhook events--for example, when receiving webhook notifications from a service like Slack or GitHub where you don't have control over the payload the service is sending--add `/raw` to the end of the Adafruit IO webhook URL that you share with the service.
## Notify Webhooks
If you only want to be notified that an event has happened, rather than have to handle all the data from an event--for example, if a service like GitHub is trying to send 7KB of JSON to your ESP8266--add `/notify` to the end of your Adafruit IO webhook URL. When data arrives, your feed will receive the message "ping".

View file

@ -1,164 +0,0 @@
# Actions
Actions are a way to do something when a certain situation occurs. There are two kinds of actions supported at this time: Scheduled and Reactive.
Scheduled actions repeatedly perform an action after a scheduled interval.
Reactive actions are much more advanced, and can integrate basic logic. At a basic level, they check if a feed value is somehow comparable to a value or to even another feed. If so, youll be able to send an email notification, post a webhook or even publish a message to another feed. For example, you can set up a reactive action to notify you when the temperature falls below a certain value. When paired with Feed Notification you can easily keep track of the health of your feed and also when somethings gone wrong.
## Get All Actions
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/actions</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/actions
```
> Response Sample:
```json
[
{
"name": "string"
}
]
```
An array of actions
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
## Create Action
> HTTP Request
> <div class="http"><span class="method-post">POST</span><code class="path">/api/v2/{username}/actions</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/actions
```
> Response Sample:
```json
{
"name": "string"
}
```
New Action
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
trigger | object | true |
## Return Action
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/actions/{id}</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/actions/{id}
```
> Response Sample:
```json
{
"name": "string"
}
```
Action response
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
id | string | true |
## Replace Action
> HTTP Request
> <div class="http"><span class="method-put">PUT</span><code class="path">/api/v2/{username}/actions/{id}</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/actions/{id}
```
> Response Sample:
```json
{
"name": "string"
}
```
Updated action
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
id | string | true |
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
trigger | object | true |
## Delete Action
> HTTP Request
> <div class="http"><span class="method-delete">DELETE</span><code class="path">/api/v2/{username}/actions/{id}</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/actions/{id}
```
> Response Sample:
```json
"string"
```
Deleted Action successfully
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
id | string | true |

View file

@ -1,119 +0,0 @@
# Activities
Activities are Adafruit IO's list of actions you've taken to create, update, or
delete objects in your Adafruit IO account. We store the last 1000 actions taken for:
* Dashboards
* Blocks
* Feeds
* Groups
* Actions
## All Activities
> HTTP Request
> <div class="http"><span class="method-get">GET</span> <code class="path">/api/v2/{username}/activities</code></div>
```shell
curl -H "X-AIO-Key: {io_key}" \
https://io.adafruit.com/api/v2/{username}/activities
```
```python
```
```cpp
```
```ruby
```
> Response Sample
```json
[
{
"id": 0,
"action": "string",
"model": "string",
"data": {
},
"user_id": 0,
"created_at": "string",
"updated_at": "string"
}
]
```
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
### Query Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
start_time | string | false | Start time for filtering, returns records created after given time.
end_time | string | false | End time for filtering, returns records created before give time.
limit | integer | false | Limit the number of records returned.
## Get Activities by Type
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/activities/{type}</code></div>
```shell
# Returns two records
$ curl -F 'limit=2' -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/activities/{type}
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
[
{
"id": 0,
"action": "string",
"model": "string",
"data": {
},
"user_id": 0,
"created_at": "string",
"updated_at": "string"
}
]
```
An array of activities
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
type | string | true |
### Query Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
start_time | string | false | Start time for filtering, returns records created after given time.
end_time | string | false | End time for filtering, returns records created before give time.
limit | integer | false | Limit the number of records returned.

View file

@ -1,264 +0,0 @@
# Blocks
Blocks are objects which can be placed on an Adafruit IO Dasboard for a user.
Blocks IO range from input blocks (sliders and buttons) to output blocks (such as maps or other visual displays).
The `dashboard_key` can be obtained by either the response of a dashboard API call, or via the UI within IO at https://io.adafruit.com/{username}/dashboards.
## All blocks
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/dashboards/{dashboard_key}/blocks</code></div>
```shell
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
[
{
"name": "string",
"description": "string",
"key": "string",
"visual_type": "string",
"column": 0,
"row": 0,
"size_x": 0,
"size_y": 0,
"block_feeds": [
{
"id": "string",
"feed": null,
"group": null
}
]
}
]
```
An array of blocks
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
dashboard_key | string | true |
## Create a Block
> HTTP Request
> <div class="http"><span class="method-post">POST</span><code class="path">/api/v2/{username}/dashboards/{dashboard_key}/blocks</code></div>
```shell
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
{
"name": "string",
"description": "string",
"key": "string",
"visual_type": "string",
"column": 0,
"row": 0,
"size_x": 0,
"size_y": 0,
"block_feeds": [
{
"id": "string",
"feed": null,
"group": null
}
]
}
```
New Block
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
dashboard_key | string | true |
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
block | object | true |
## Returns Block
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/dashboards/{dashboard_key}/blocks/{id}</code></div>
```shell
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
{
"name": "string",
"description": "string",
"key": "string",
"visual_type": "string",
"column": 0,
"row": 0,
"size_x": 0,
"size_y": 0,
"block_feeds": [
{
"id": "string",
"feed": null,
"group": null
}
]
}
```
Block response
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
dashboard_key | string | true |
id | string | true |
## Replace A Block
> HTTP Request
> <div class="http"><span class="method-put">PUT</span><code class="path">/api/v2/{username}/dashboards/{dashboard_key}/blocks/{id}</code></div>
```shell
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
{
"name": "string",
"description": "string",
"key": "string",
"visual_type": "string",
"column": 0,
"row": 0,
"size_x": 0,
"size_y": 0,
"block_feeds": [
{
"id": "string",
"feed": null,
"group": null
}
]
}
```
Updated block
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
dashboard_key | string | true |
id | string | true |
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
block | object | true |
## Delete a Block
> HTTP Request
> <div class="http"><span class="method-delete">DELETE</span><code class="path">/api/v2/{username}/dashboards/{dashboard_key}/blocks/{id}</code></div>
```shell
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
"string"
```
Deleted Block successfully
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
dashboard_key | string | true |
id | string | true |

View file

@ -1,304 +0,0 @@
# Dashboards
Dashboards allow you to visualize data and control Adafruit IO connected projects from any modern web browser.
Blocks such as charts, sliders, and buttons are available to help you quickly get your IoT project up and running without the need
for any custom code.
## All dashboards
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/dashboards</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/dashboards
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
[
{
"name": "string",
"description": "string",
"key": "string",
"blocks": [
{
"name": "string",
"description": "string",
"key": "string",
"visual_type": "string",
"column": 0,
"row": 0,
"size_x": 0,
"size_y": 0,
"block_feeds": [
{
"id": "string",
"feed": null,
"group": null
}
]
}
]
}
]
```
An array of dashboards
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
## Create a Dashboard
> HTTP Request
> <div class="http"><span class="method-post">POST</span><code class="path">/api/v2/{username}/dashboards</code></div>
```shell
$ curl -F 'name=newdash' -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/dashboards
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
{
"name": "string",
"description": "string",
"key": "string",
"blocks": [
{
"name": "string",
"description": "string",
"key": "string",
"visual_type": "string",
"column": 0,
"row": 0,
"size_x": 0,
"size_y": 0,
"block_feeds": [
{
"id": "string",
"feed": null,
"group": null
}
]
}
]
}
```
New Dashboard
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
dashboard | object | true |
## Return Dashboard
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/dashboards/{id}</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/dashboards/{id}
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
{
"name": "string",
"description": "string",
"key": "string",
"blocks": [
{
"name": "string",
"description": "string",
"key": "string",
"visual_type": "string",
"column": 0,
"row": 0,
"size_x": 0,
"size_y": 0,
"block_feeds": [
{
"id": "string",
"feed": null,
"group": null
}
]
}
]
}
```
Dashboard response
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
id | string | true |
## Replace a Dashboard
> HTTP Request
> <div class="http"><span class="method-put">PUT</span><code class="path">/api/v2/{username}/dashboards/{id}</code></div>
```shell
$ curl -F 'name=newdash' -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/dashboards/{id}
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
{
"name": "string",
"description": "string",
"key": "string",
"blocks": [
{
"name": "string",
"description": "string",
"key": "string",
"visual_type": "string",
"column": 0,
"row": 0,
"size_x": 0,
"size_y": 0,
"block_feeds": [
{
"id": "string",
"feed": null,
"group": null
}
]
}
]
}
```
Updated dashboard
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
id | string | true |
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
dashboard | object | true |
## Delete a Dashboard
> HTTP Request
> <div class="http"><span class="method-delete">DELETE</span><code class="path">/api/v2/{username}/dashboards/{id}</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/dashboards/{id}
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
"string"
```
Deleted Dashboard successfully
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
id | string | true |

View file

@ -1,769 +0,0 @@
# Data
Data is at the heart of Adafruit IO. Everything your device measures and records becomes a data point on an Adafruit IO <a href="#feeds">Feed</a>.
You can create, read, update, or delete data records. Every **CREATE**, **UPDATE**, or **DELETE** action on a data record counts against your rate limit.
Data points belong to feeds, so every Data API call starts with a Feed URL.
Note that there are endpoints for submitting multiple data points to a feed, and multiple feed values to a group, see **feeds/{feed_key}/batch** and **groups/{groupname}/data** endpoints.
## Create Data
> HTTP Request
> <div class="http"><span class="method-post">POST</span><code class="path">/api/v2/{username}/feeds/{feed_key}/data</code></div>
```shell
# Send new data with a value of 42 (note: using single quotes instead prevents variable expansion etc in bash)
$ curl -F "value=42" -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/feeds/{feed_key}/data
# Send new data with a value of 42 and include optional location metadata
curl -H "Content-Type: application/json" -d '{"value": 42, "lat": 23.1, "lon": "-73.3"}' -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/feeds/{feed_key}/data
```
```python
# Adafruit IO Python
# Send data to feed feed_name with a value of 42
io.send_data(location_feed.key, '42')
# Send data to feed `feed_name` with a value of 42 and include optional location metadata
metadata = {'lat': 40.726190,
'lon': -74.005334,
'ele': -6,
'created_at': None}
io.send_data(feed_name.key, data_value, metadata)
# Adafruit IO CircuitPython
# Send data to feed feed_name with a value of 42
io.send_data(location_feed['key'], '42')
# Send data to feed `feed_name` with a value of 42 and include optional location metadata
metadata = {'lat': 40.726190,
'lon': -74.005334,
'ele': -6,
'created_at': None}
io.send_data(feed_name['key'], data_value, metadata)
```
```cpp
// Send data to Feed `feedName` with value of 42
feedName->save(42);
// Send data to Feed `feedName` with value 42 and include optional location metadata
feedName->save(42, latValue, lonValue, eleValue);
```
```ruby
```
> Response Sample:
<%= partial 'responses/datum' %>
New data
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
<b>Request Body</b> | object | true | Data record (datum) including a `value` field (required) and optionally including: `lat`, `lon`, `ele` (latitude, longitude, and elevation values), and `created_at` (a date/time string).
## Get Feed Data
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/feeds/{feed_key}/data</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/feeds/{feed_key}/data
# get the most recent value
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/feeds/{feed_key}/data?limit=1
# get the most recent value before a particular time
$ curl -H "X-AIO-Key: {io_key}" "https://io.adafruit.com/api/v2/{username}/feeds/{feed_key}/data?limit=1&end_time=2019-05-05T00:00Z"
# get all values in a date range
$ curl -H "X-AIO-Key: {io_key}" "https://io.adafruit.com/api/v2/{username}/feeds/{feed_key}/data?start_time=2019-05-04T00:00Z&end_time=2019-05-05T00:00Z"
```
```cpp
// Not implemented in Adafruit IO Arduino
```
```python
# Not implemented in Adafruit IO Python
# Not implemented in Adafruit IO CircuitPython
```
> Response Sample:
<%= partial 'responses/data' %>
### Response Parameters
An array of zero or more data points.
This API is paginated.
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key
### Query Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
start_time | string | false | Start time for filtering, returns records created after given time. Use [ISO8601 formatted dates](https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations).
end_time | string | false | End time for filtering, returns records created before give time. Use [ISO8601 formatted dates](https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations).
limit | integer | false | Limit the number of records returned.
include | csv string | false | List of Data record fields to include in response records. Acceptable values are: `value`, `lat`, `lon`, `ele`, `id`, and `created_at`.
before | string | false | System generated token used to produce the next page of data. See [The Link Header](#the-link-header) for details.
## Chart Feed Data
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/feeds/{feed_key}/data/chart</code></div>
```shell
# Query the chart API for the previous hour.
$ curl -H "X-AIO-Key: {io_key}" 'https://io.adafruit.com/api/v2/{username}/feeds/{feed_key}/data/chart?hours=1'
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
{
"feed": {
"id": 0,
"key": "string",
"name": "string"
},
"parameters": {
"start_time": "2019-02-28T16:17:09Z",
"end_time": "2019-04-29T16:17:09Z",
"resolution": 120,
"hours": 1440,
"field": "avg"
},
"columns": ["date", "avg"],
"data": [
[ "2019-03-01T14:00:00Z", "62.579827586206896" ],
[ "2019-03-02T18:00:00Z", "64.94642857142857" ],
[ "...", "..."]
]
}
```
A JSON record containing chart data and the parameters used to generate it. This API will automatically calculate `resolution` based on the optimal time slice for the given `start_time` to `end_time` range or `hours` value given.
Charts on io.adafruit.com use this API with only the `hours` parameter to render charts on dashboards and feed pages.
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key
### Query Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
start_time | string | false | Start time for filtering, returns records created after given time. Use [ISO8601 formatted dates](https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations).
end_time | string | false | End time for filtering, returns records created before give time. Use [ISO8601 formatted dates](https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations).
resolution | int | false | Size of aggregation slice in minutes. Must be one of: `1`, `5`, `10`, `30`, `60`, `120`, `240`, `480`, or `960`
hours | int | false | Number of hours to include in the chart. This value is ignored if `start_time` and `end_time` are given.
field | string | false | Aggregate field to return. Must be one of: `avg`, `sum`, `val`, `min`, `max`, `val_count`
raw | boolean | false | Force raw chart data to be returned. Not compatible with `field` or `resolution` parameters. Use `1` or `true` for boolean true value.
## Create Multiple Data Records
> HTTP Request
> <div class="http"><span class="method-post">POST</span><code class="path">/api/v2/{username}/feeds/{feed_key}/data/batch</code></div>
```shell
$ curl -H "Content-Type: application/json" -d @batch.json -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/feeds/{feed_key}/data/batch
```
```python
# Adafruit IO Python
data_list = [Data(value=50), Data(value=33)]
aio.send_batch_data(feed_name.key, data_list)
# Not implemented in Adafruit IO CircuitPython
```
```cpp
```
```ruby
```
> Response Sample:
<%= partial 'responses/data' %>
New data
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
data | array | true | A collection of data records including `value` (required) and optionally including: `lat`, `lon`, `ele` (latitude, longitude, and elevation values), and `created_at` (a date/time string).
## Get Previous Data
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/feeds/{feed_key}/data/previous</code></div>
```shell
```
```python
# Adafruit IO Python
data = aio.receive_previous(feed.key)
```
```cpp
```
```ruby
```
> Response Sample:
<%= partial 'responses/datum' %>
Data response
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key
### Query Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
include | string | false | List of Data record fields to include in response as comma separated list. Acceptable values are: `value`, `lat`, `lon`, `ele`, `id`, and `created_at`.
## Get Next Data
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/feeds/{feed_key}/data/next</code></div>
```shell
```
```python
# Adafruit IO Python
data = aio.receive_next(feed.key)
```
```cpp
```
```ruby
```
> Response Sample:
<%= partial 'responses/datum' %>
Data response
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key
### Query Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
include | string | false | List of Data record fields to include in response as comma separated list. Acceptable values are: `value`, `lat`, `lon`, `ele`, `id`, and `created_at`.
## Get Last Data
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/feeds/{feed_key}/data/last</code></div>
```shell
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
<%= partial 'responses/datum' %>
Data response
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key
### Query Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
include | string | false | List of Data record fields to include in response as comma separated list. Acceptable values are: `value`, `lat`, `lon`, `ele`, `id`, and `created_at`.
## Get First Data
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/feeds/{feed_key}/data/first</code></div>
```shell
```
```python
# Adafruit IO Python
data = aio.receive(feed.key)
```
```cpp
```
```ruby
```
> Response Sample:
<%= partial 'responses/datum' %>
Data response.
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key
### Query Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
include | string | false | List of Data record fields to include in response as comma separated list. Acceptable values are: `value`, `lat`, `lon`, `ele`, `id`, and `created_at`.
## Get Most Recent Data
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/feeds/{feed_key}/data/retain</code></div>
```shell
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```csv
"string",0.0,0.0,0.0
```
CSV string in `value,lat,lon,ele` format. The lat, lon, and ele values are left blank if they are not set.
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key
## Get Data Point
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/feeds/{feed_key}/data/{id}</code></div>
```shell
```
```python
# Adafruit IO Python
data = aio.receive(feed_name.key)
# Adafruit IO CircuitPython
data = aio.receive(feed_name['key'])
```
```cpp
```
```ruby
```
> Response Sample:
<%= partial 'responses/datum' %>
Data response
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key
id | string | true |
### Query Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
include | string | false | List of Data record fields to include in response as comma separated list. Acceptable values are: `value`, `lat`, `lon`, `ele`, `id`, and `created_at`.
## Update Data Point
> HTTP Request
> <div class="http"><span class="method-put">PUT</span><code class="path">/api/v2/{username}/feeds/{feed_key}/data/{id}</code></div>
```shell
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
<%= partial 'responses/datum' %>
Updated Data
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key
id | string | true |
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
<b>Request Body</b> | object | true | Data record (datum) including a `value` field (required) and optionally including: `lat`, `lon`, `ele` (latitude, longitude, and elevation values), and `created_at` (a date/time string).
## Delete Data Point
> HTTP Request
> <div class="http"><span class="method-delete">DELETE</span><code class="path">/api/v2/{username}/feeds/{feed_key}/data/{id}</code></div>
```shell
```
```python
# Adafruit IO Python
aio.delete(feed_name.key, data_id)
# Adafruit IO CircuitPython
aio.delete_data(feed_name['key'], data_id)
```
```cpp
```
```ruby
```
> Response Sample:
```json
```
Deleted Group successfully
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key
id | string | true |
## Create Group Data
> HTTP Request
> <div class="http"><span class="method-post">POST</span><code class="path">/api/v2/{username}/groups/{group_key}/data</code></div>
```shell
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
<%= partial 'responses/datum' %>
New data
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
group_key | string | true |
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
group_feed_data | object | true | A record with the `feeds` property, containing a collection of records with `key` and `value` properties.
Example for `group_feed_data` in the body is as follows: `{ feeds: [ { key: string, value: string }, ... ], created_at: string (optional), location: { lat: number, lon: number, ele: number } (optional)}`
## Get Data for Group's Feed
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/groups/{group_key}/feeds/{feed_key}/data</code></div>
```shell
# Get data from the given Feed in the given Group
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/groups/{group_key}/feeds/{feed_key}/data
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
<%= partial 'responses/datum' %>
An array of data
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
group_key | string | true |
feed_key | string | true | a valid feed key
## Create Data in a Group's Feed
> HTTP Request
> <div class="http"><span class="method-post">POST</span><code class="path">/api/v2/{username}/groups/{group_key}/feeds/{feed_key}/data</code></div>
```shell
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
<%= partial 'responses/datum' %>
New data
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
group_key | string | true |
feed_key | string | true | a valid feed key
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
<b>Request Body</b> | object | true | Data record (datum) including a `value` field (required) and optionally including: `lat`, `lon`, `ele` (latitude, longitude, and elevation values), and `created_at` (a date/time string).
## Create Data in a Group's Feed
> HTTP Request
> <div class="http"><span class="method-post">POST</span><code class="path">/api/v2/{username}/groups/{group_key}/feeds/{feed_key}/data/batch</code></div>
```shell
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
<%= partial 'responses/data' %>
New data
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
group_key | string | true |
feed_key | string | true | a valid feed key
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
data | array | true | A collection of data records including `value` (required) and optionally including: `lat`, `lon`, `ele` (latitude, longitude, and elevation values), and `created_at` (a date/time string).

View file

@ -1,615 +0,0 @@
# Feeds
Feeds are the core of the Adafruit IO system. The feed holds metadata about the data you push to Adafruit IO. This includes settings for whether the data is public or private, what license the stored data falls under, and a general description of the data. The feed also contains the sensor data values that get pushed to Adafruit IO from your device.
You will need to create one feed for each unique source of data you send to Adafruit IO.
You can create, read, update, or delete feeds. Every **CREATE**, **UPDATE**, or **DELETE** action on a feed record counts against your rate limit.
There are also endpoints for submitting multiple data points to a feed, or multiple feed values to a group, see **feeds/{feed_key}/batch** and **groups/{groupname}/data** endpoints.
## All Feeds
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/feeds</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/feeds/
```
```python
# Adafruit IO Python
feeds = aio.feeds()
# Not implemented in Adafruit IO CircuitPython
```
> Response Sample:
```json
[
{
"id": 0,
"name": "string",
"key": "string",
"group": {
"id": 0,
"name": "string",
"description": "string",
"created_at": "string",
"updated_at": "string"
},
"groups": [
{
"id": 0,
"name": "string",
"description": "string",
"created_at": "string",
"updated_at": "string"
}
],
"description": "string",
"details": {
"shared_with": null,
"data": {
"first": {
"id": "string",
"value": "string",
"feed_id": 0,
"group_id": 0,
"expiration": "string",
"lat": 0,
"lon": 0,
"ele": 0,
"completed_at": "string",
"created_at": "string",
"updated_at": "string",
"created_epoch": 0
},
"last": {
"id": "string",
"value": "string",
"feed_id": 0,
"group_id": 0,
"expiration": "string",
"lat": 0,
"lon": 0,
"ele": 0,
"completed_at": "string",
"created_at": "string",
"updated_at": "string",
"created_epoch": 0
},
"count": 0
}
},
"unit_type": "string",
"unit_symbol": "string",
"history": true,
"visibility": "string",
"license": "string",
"enabled": true,
"last_value": "string",
"status": "string",
"status_notify": true,
"status_timeout": 0,
"created_at": "string",
"updated_at": "string"
}
]
```
An array of feeds
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
## Create Feed
> HTTP Request
> <div class="http"><span class="method-post">POST</span><code class="path">/api/v2/{username}/feeds</code></div>
```shell
$ curl -X POST -H "Content-Type: application/json" -H "X-AIO-Key: {io_key}" \
--data '{"feed": {"name": "New Feed"}}' \
/{username}/feeds
```
```cpp
AdafruitIO_Feed *newFeed = io.feed("newfeed");
```
```python
# Adafruit IO Python
new_feed = Feed(name="newfeed")
aio.create_feed(new_feed)
# Adafruit IO CircuitPython
new_feed = io.create_new_feed('newfeed')
```
```ruby
puts "create"
Feed = api.create_feed(name: "Feed #{SecureRandom.hex(4)}")
```
> Response Sample:
```json
{
"id": 0,
"name": "string",
"key": "string",
"group": {
"id": 0,
"name": "string",
"description": "string",
"created_at": "string",
"updated_at": "string"
},
"groups": [
{
"id": 0,
"name": "string",
"description": "string",
"created_at": "string",
"updated_at": "string"
}
],
"description": "string",
"details": {
"shared_with": null,
"data": {
"first": {
"id": "string",
"value": "string",
"feed_id": 0,
"group_id": 0,
"expiration": "string",
"lat": 0,
"lon": 0,
"ele": 0,
"completed_at": "string",
"created_at": "string",
"updated_at": "string",
"created_epoch": 0
},
"last": {
"id": "string",
"value": "string",
"feed_id": 0,
"group_id": 0,
"expiration": "string",
"lat": 0,
"lon": 0,
"ele": 0,
"completed_at": "string",
"created_at": "string",
"updated_at": "string",
"created_epoch": 0
},
"count": 0
}
},
"unit_type": "string",
"unit_symbol": "string",
"history": true,
"visibility": "string",
"license": "string",
"enabled": true,
"last_value": "string",
"status": "string",
"status_notify": true,
"status_timeout": 0,
"created_at": "string",
"updated_at": "string"
}
```
New feed
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
### Query Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
group_key | string | false |
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
feed | object | true |
## Get Feed
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/feeds/{feed_key}</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" /{username}/feeds/{feed_key}
```
```python
# Adafruit IO Python
new_feed = aio.feeds('feedkey')
# Adafruit IO CircuitPython
new_feed = io.get_feed('feedkey')
```
```ruby
puts "read?"
# ... get 404
begin
api.feed(feedname['key'])
rescue => ex
if ex.response.status === 404
puts "expected error #{ex.response.status}: #{ex.message}"
else
puts "unexpected error! #{ex.message}"
end
end
```
> Response Sample:
```json
{
"id": 0,
"name": "string",
"key": "string",
"group": {
"id": 0,
"name": "string",
"description": "string",
"created_at": "string",
"updated_at": "string"
},
"groups": [
{
"id": 0,
"name": "string",
"description": "string",
"created_at": "string",
"updated_at": "string"
}
],
"description": "string",
"details": {
"shared_with": null,
"data": {
"first": {
"id": "string",
"value": "string",
"feed_id": 0,
"group_id": 0,
"expiration": "string",
"lat": 0,
"lon": 0,
"ele": 0,
"completed_at": "string",
"created_at": "string",
"updated_at": "string",
"created_epoch": 0
},
"last": {
"id": "string",
"value": "string",
"feed_id": 0,
"group_id": 0,
"expiration": "string",
"lat": 0,
"lon": 0,
"ele": 0,
"completed_at": "string",
"created_at": "string",
"updated_at": "string",
"created_epoch": 0
},
"count": 0
}
},
"unit_type": "string",
"unit_symbol": "string",
"history": true,
"visibility": "string",
"license": "string",
"enabled": true,
"last_value": "string",
"status": "string",
"status_notify": true,
"status_timeout": 0,
"created_at": "string",
"updated_at": "string"
}
```
Feed response
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key
## Update Feed
> HTTP Request
> <div class="http"><span class="method-put">PUT</span><code class="path">/api/v2/{username}/feeds/{feed_key}</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/feeds/{feed_key}
```
```cpp
// Not implemented in Adafruit IO Arduino
```
```python
# Not implemented in Adafruit IO Python
# Not implemented in Adafruit IO CircuitPython
```
> Response Sample:
```json
{
"id": 0,
"name": "string",
"key": "string",
"group": {
"id": 0,
"name": "string",
"description": "string",
"created_at": "string",
"updated_at": "string"
},
"groups": [
{
"id": 0,
"name": "string",
"description": "string",
"created_at": "string",
"updated_at": "string"
}
],
"description": "string",
"details": {
"shared_with": null,
"data": {
"first": {
"id": "string",
"value": "string",
"feed_id": 0,
"group_id": 0,
"expiration": "string",
"lat": 0,
"lon": 0,
"ele": 0,
"completed_at": "string",
"created_at": "string",
"updated_at": "string",
"created_epoch": 0
},
"last": {
"id": "string",
"value": "string",
"feed_id": 0,
"group_id": 0,
"expiration": "string",
"lat": 0,
"lon": 0,
"ele": 0,
"completed_at": "string",
"created_at": "string",
"updated_at": "string",
"created_epoch": 0
},
"count": 0
}
},
"unit_type": "string",
"unit_symbol": "string",
"history": true,
"visibility": "string",
"license": "string",
"enabled": true,
"last_value": "string",
"status": "string",
"status_notify": true,
"status_timeout": 0,
"created_at": "string",
"updated_at": "string"
}
```
Updated feed
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
feed | object | true |
## Delete Feed
> HTTP Request
> <div class="http"><span class="method-delete">DELETE</span><code class="path">/api/v2/{username}/feeds/{feed_key}</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/feeds/{feed_key}
```
```python
# Adafruit IO Python
io.delete_feed(feed_name.key)
# Adafruit IO CircuitPython
io.delete_feed(feed_name['key'])
```
```ruby
puts "delete"
api.delete_feed(feed)
```
> Response Sample:
```json
```
Deleted feed successfully
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key
## Get Feed
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/feeds/{feed_key}/details</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/feeds/{feed_key}/details
```
```cpp
// Not implemented in Adafruit IO Arduino
```
```python
# Not implemented in Adafruit IO Python
# Not implemented in Adafruit IO CircuitPython
```
```ruby
puts "read"
puts JSON.pretty_generate(api.feed_details(feed))
```
> Response Sample:
```json
{
"id": 0,
"name": "string",
"key": "string",
"group": {
"id": 0,
"name": "string",
"description": "string",
"created_at": "string",
"updated_at": "string"
},
"groups": [
{
"id": 0,
"name": "string",
"description": "string",
"created_at": "string",
"updated_at": "string"
}
],
"description": "string",
"details": {
"shared_with": null,
"data": {
"first": {
"id": "string",
"value": "string",
"feed_id": 0,
"group_id": 0,
"expiration": "string",
"lat": 0,
"lon": 0,
"ele": 0,
"completed_at": "string",
"created_at": "string",
"updated_at": "string",
"created_epoch": 0
},
"last": {
"id": "string",
"value": "string",
"feed_id": 0,
"group_id": 0,
"expiration": "string",
"lat": 0,
"lon": 0,
"ele": 0,
"completed_at": "string",
"created_at": "string",
"updated_at": "string",
"created_epoch": 0
},
"count": 0
}
},
"unit_type": "string",
"unit_symbol": "string",
"history": true,
"visibility": "string",
"license": "string",
"enabled": true,
"last_value": "string",
"status": "string",
"status_notify": true,
"status_timeout": 0,
"created_at": "string",
"updated_at": "string"
}
```
Feed response
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
feed_key | string | true | a valid feed key

File diff suppressed because it is too large Load diff

View file

@ -1,44 +0,0 @@
# Pagination
Adafruit IOs API returns at most 1000 data points at a time. To get more data if your feed is over 1000 data points, youll need to “paginate” the data.
What does this mean?
When you perform <a href="#get-all-data-for-the-given-feed">an HTTP data GET query</a>, the results are always sorted newest-to-oldest and include 5 `X-Pagination-*` headers and [the Link header field](https://tools.ietf.org/html/rfc5988#section-5) in the response. You can see an example of the headers on the right.
## Pagination Headers
```yaml
X-Pagination-Count: 250
X-Pagination-Limit: 250
X-Pagination-Total: 83027
X-Pagination-Start:
X-Pagination-End: 2019-05-03T17:35:13.637+0000
Link: <https://io.adafruit.com/api/v2/abachman/feeds/humidity/data?end_time=2019-05-03+17%3A35%3A13+UTC&limit=250>;rel="next", <https://io.adafruit.com/api/v2/abachman/feeds/humidity/data?before=eyJ0aW1lX2lkIjoiMEU1M043N0syUjdUR1Y3MEY3UjJFUVlRVlkiLCJmZWVkX2lkIjoiNjE3MzcwLjAifQ%3D%3D&end_time=2019-05-03+17%3A35%3A13+UTC&limit=250>
```
* **Count** (`X-Pagination-Count`) is the number of data points in the current request.
* **Limit** (`X-Pagination-Limit`) is either the requested limit if it was included as a parameter or 1000, whichever is less.
* **Total** (`X-Pagination-Total`) is the total number of data points in the feed for the given `start_time` and `end_time`. *Note, this value may be up to 5 minutes behind real time.*
* **Start** (`X-Pagination-Start`) is an ISO-8601 formatted date value based on the `start_time` parameter in the original request, if one was given.
* **End** (`X-Pagination-End`) is an ISO-8601 formatted date value based either on the `end_time` parameter from the original request or the time when the original request was made.
* **Link** is a set of one or more URLs that point you to related resources.
Whenever **Limit** and **Count** are both 1000 and **Total** is more than 1000, thats evidence that more data is available. That's where the **Link** (`Link`) header comes in.
## The Link Header
For Adafruit IO **Link** always contains at least one URL inside angle brackets, that's the link to the page of data you are currently looking at. In the example above, the first URL is `https://io.adafruit.com/api/v2/abachman/feeds/example.counter-1/data?end_time=2019-05-02+22%3A33%3A22+UTC&limit=250`. The first URL given in the **Link** header can be used to request the same data set again in the future. Even if your original request didn't include any parameters, the **Link** URL will include a `start_time` parameter that reflects the time at which you made the request. This is how we can make sure you can request the same data repeatedly.
The example **Link** value above also includes a *next* section: `rel="next", <https://io.adafruit.com/api/v2/abachman/feeds/example.counter-1/data?before=eyJ0aW1lX2lkIjoiMEU0V0RWSk1SNlgxNUgxV0FSR0c2SzFIRUgiLCJmZWVkX2lkIjoiNzMuMCJ9&end_time=2019-05-02+22%3A33%3A22+UTC&limit=250>`. The `rel="next"` part means the URL that follows is a link to the *next page* of data. As long as there is more data available, the **Link** header will include a `rel="next"` URL. It updates on each request, so you can page through data by making a request, parsing the **Link** header to get a next URL, and then using that URL to make another request. If your initial request includes `end_time`, `start_time`, or `limit` parameters, those parameters will be included in the `rel="next"` URL. Note that since data request are always sorted by descending `created_at` date (newest first, oldest last), the next page of data is always the next older page of data.
When visualized on a timeline, the concept of pagination looks like this:
<%= image_tag "images/http/api-pagination.png" %>
Note that long running, frequently updated feeds could have more than a hundred pages of data. In the example above, with a limit of 250 records, it would take 330 requests to get all the data. If you make requests without a small delay in between, you will hit a rate limit. To avoid this, watch for 429 HTTP error responses and handle them in code by adding a 30 second timeout between requests and request the largest size permitted, right now that's 1000 records.
If your goal is to store and study the data offline, though, you would be better off downloading the whole feed using the Download button built into Adafruit IO on the web.
You can find an example of a paginated data downloading script in Python [at this link](https://gist.github.com/abachman/12df0b34503edd5692be22f6b9695539). Stop by [the forums](https://forums.adafruit.com/viewforum.php?f=56) or [Discord](https://discord.gg/adafruit) if you have more questions about getting your Data out of IO.

View file

@ -1,251 +0,0 @@
# Permissions
Each Adafruit IO user contains permissions which can be set and modified.
## Get All Permissions
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/{type}/{type_id}/acl</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/{type}/{type_id}/acl
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
[
{
"id": 0,
"user_id": 0,
"scope": "string",
"scope_value": "string",
"model": "string",
"object_id": 0,
"created_at": "string",
"updated_at": "string"
}
]
```
An array of permissions
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
type | string | true |
type_id | string | true |
## Create Permission
> HTTP Request
> <div class="http"><span class="method-post">POST</span><code class="path">/api/v2/{username}/{type}/{type_id}/acl</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/{type}/{type_id}/acl
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
{
"id": 0,
"user_id": 0,
"scope": "string",
"scope_value": "string",
"model": "string",
"object_id": 0,
"created_at": "string",
"updated_at": "string"
}
```
New Permission
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
type | string | true |
type_id | string | true |
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
permission | object | true |
## Returns Permission
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/{type}/{type_id}/acl/{id}</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/{type}/{type_id}/acl{id}
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
{
"id": 0,
"user_id": 0,
"scope": "string",
"scope_value": "string",
"model": "string",
"object_id": 0,
"created_at": "string",
"updated_at": "string"
}
```
Permission response
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
type | string | true |
type_id | string | true |
id | string | true |
## Replace Permission
> HTTP Request
> <div class="http"><span class="method-put">PUT</span><code class="path">/api/v2/{username}/{type}/{type_id}/acl/{id}</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/{type}/{type_id}/acl{id}
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
{
"id": 0,
"user_id": 0,
"scope": "string",
"scope_value": "string",
"model": "string",
"object_id": 0,
"created_at": "string",
"updated_at": "string"
}
```
Updated permission
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
type | string | true |
type_id | string | true |
id | string | true |
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
permission | object | true |
## Delete Permission
> HTTP Request
> <div class="http"><span class="method-delete">DELETE</span><code class="path">/api/v2/{username}/{type}/{type_id}/acl/{id}</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/{type}/{type_id}/acl{id}
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
"string"
```
Deleted Permission successfully
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
type | string | true |
type_id | string | true |
id | string | true |

View file

@ -1,32 +0,0 @@
# Services
Adafruit IO provides access to several connected services. The current services offered are [IFTTT](https://io.adafruit.com/services/ifttt), [Zapier](https://io.adafruit.com/services/zapier), [Weather](https://io.adafruit.com/services/weather), [Randomizer](https://io.adafruit.com/services/words) and [Time](https://io.adafruit.com/services/time).
Each of these services is unique in that you may need to do some setup at the links above prior to utilizing the service via the Adafruit IO HTTP API.
## Time
The Adafruit IO time service does not replace a time-synchronization service like NTP, but it can help you figure out your local time on an Internet of Things device that doesn't have a built in clock.
Detailed documentation on the usage of the time API is found within [Adafruit IO on the time services page](https://io.adafruit.com/services/time).
## Randomizer
Create random data streams that can generate colors, words, numbers, or pick a value from a custom data set and send it directly to your devices.
The four available data types are:
* Pronounceable nonsense words
* Colors (RGB values, HSL values, CSS hex, or CSS color name)
* Numbers
* Preset (sample from a given set of values)
Detailed documentation on the usage and setup of the randomizer API is found within [Adafruit IO on the randomizer services page](https://io.adafruit.com/services/words).
## Weather
With access to weather data powered by Dark Sky, you can get hyper-local forecasts sent directly to your devices. Weather data is updated at most once every 20 minutes.
When you have an IO Plus account, you can track the weather through our HTTP or MQTT APIs for up to 5 locations at a time.
Detailed documentation on the usage and setup of the weather API is found within [Adafruit IO on the weather services page](https://io.adafruit.com/services/weather).

View file

@ -1,174 +0,0 @@
# Tokens
Tokens are used for authenticating an Adafruit IO user. See the _Authentication_ page for more information about this.
## Get All Tokens
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/tokens</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/tokens
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
[
{
"token": "string"
}
]
```
An array of tokens
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
## Create Token
> HTTP Request
> <div class="http"><span class="method-post">POST</span><code class="path">/api/v2/{username}/tokens</code></div>
```shell
$ curl -F 'token=uniqueToken' -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/tokens
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
{
"token": "string"
}
```
New Token
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
token | object | true |
## Returns Token
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/tokens/{id}</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/tokens/{id}
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
{
"token": "string"
}
```
Token response
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
id | string | true |
## Delete Token
> HTTP Request
> <div class="http"><span class="method-delete">DELETE</span><code class="path">/api/v2/{username}/tokens/{id}</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/tokens/{id}
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
```json
"string"
```
Deleted Token successfully
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string
id | string | true |

View file

@ -1,67 +0,0 @@
# Users
Adafruit IO can return information about your username, activity-level, rate-limit and current actions.
## Get User Info
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/user</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/user
```
> Response Sample:
```json
{
"id": 0,
"name": "string",
"color": "string",
"username": "string",
"time_zone": "string",
"created_at": "string",
"updated_at": "string"
}
```
A User record
## Get Detailed User Info
> HTTP Request
> <div class="http"><span class="method-get">GET</span><code class="path">/api/v2/{username}/throttle</code></div>
```shell
$ curl -H "X-AIO-Key: {io_key}" https://io.adafruit.com/api/v2/{username}/throttle
```
> Response Sample:
```json
{
"data_rate_limit": 0,
"active_data_rate": 0
}
```
Data rate limit and current actions.
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
username | string | true | a valid username string

View file

@ -1,127 +0,0 @@
# Webhooks
Webhooks are one way disconnected web services can share data with each other, automatically. For example, say you wanted to get a users latest Twitter message. Instead of constantly connecting to the twitter API every minute to check if a new message has been posted, you can ask Twitter to update a webhook URL on each post. That means Twitter will contact you when theres new data. But, as you can imagine, you need a webserver to listen for that posting. In this case, Adafruit IO can act as that webhook destination.
Adafruit IO only supports receiving data at this time.
<aside class="notice">
These data publishing webhook methods <strong>do not require authentication</strong>. That
means you can freely use the URL from a public form without leaking your
authentication data.
</aside>
You can create new feed webhook receivers by visiting a feed page and using the "Webhooks" link.
## Send Data via Webhook
Create a data value. The request body should include a value parameter named either `value` or `payload` and may optionally include `lat`, `lon`, and `ele` parameters if you want to tag the data with a location.
> HTTP Request
> <div class="http"><span class="method-post">POST</span><code class="path">/api/v2/webhooks/feed/:token</code></div>
```shell
# publish as form data
curl -F "value=42" https://io.adafruit.com/api/v2/webhooks/feed/:token
# publish as JSON
curl -F '{"value":"42"}' -H 'Content-Type: application/json' \
https://io.adafruit.com/api/v2/webhooks/feed/:token
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
<%= partial 'responses/datum', locals: {value: '42'} %>
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
token | string | true | the webhook token
### Body Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
value | string | true | Data value
lat | float | false | latitude value for location
lon | float | false | longitude value for location
ele | float | false | elevation value for location
## Send Arbitrary Data via Webhook
New feed data record whose value is the raw contents of the webhook request body.
Use this path if the web service you're connecting to can't be configured to match the webhook `Send Data` API body format.
> HTTP Request
> <div class="http"><span class="method-post">POST</span><code class="path">/api/v2/webhooks/feed/:token/raw</code></div>
```shell
curl -H "Content-Type: text/plain" \
--data "this is raw data, { 'not properly formatted json' }" \
https://io.adafruit.com/api/v2/webhooks/feed/:token/raw
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
<%= partial 'responses/datum', locals: { value: "this is raw data, { 'not properly formatted json' }"} %>
### Path Parameters
Parameter | Type | Required | Description
--------- | ------- | --------- | -----------------------
token | string | true | the webhook token
## Send Notification via Webhook
> HTTP Request
> <div class="http"><span class="method-post">POST</span><code class="path">/api/v2/webhooks/feed/:token/notify</code></div>
```shell
$ curl -X POST https://io.adafruit.com/api/v2/webhooks/feed/:token/notify
```
```python
```
```cpp
```
```ruby
```
> Response Sample:
<%= partial 'responses/datum', locals: { value: "ping"} %>
Creates a new feed data record with the value "ping", regardless of what was posted.
This path is helpful if you're using a low-memory MQTT client that can't handle the large webhook payloads that a service like GitHub publishes and all you care about is _that_ something happened, not _precisely what_ happened.

View file

@ -1,27 +0,0 @@
# Error Topics
Adafruit IO provides two error reporting MQTT topics you can subscribe to:
- `{username}/errors`
- `{username}/throttle`
## {username}/errors
This topic publishes error messages related to publishing and subscribing to Adafruit IO feeds. Because MQTT is an asynchronous and compact messaging format, we cannot respond to invalid PUBLISH or SUBSCRIBE packets with a comprehensive error message, so we use this topic to update subscribers when an error occurs.
You may only subscribe to your personal errors feed.
## {username}/throttle
This topic publishes throttle warning and error messages to all subscribed clients. We do our best to provide an accurate accounting in the error message of the minimum amount of time you should wait before attempting to publish again.
Be warned: exceeding the rate limit too often within a short time span will result in a temporary ban from the Adafruit IO MQTT service.
You may only subscribe to your personal throttle feed.
## Adafruit IO Monitor
Both error feeds can be seen live on [your Adafruit IO Monitor page](https://io.adafruit.com/monitor).

View file

@ -1,53 +0,0 @@
# Retained values
MQTT is a tremendously useful protocol for building small connected devices and is relatively simple to understand and implement (if implementing networking protocols is your thing). Unfortunately, a few features of the Adafruit IO platform make it difficult for us to support the entire MQTT 3.1+ protocol specification in our broker. Specifically, one particular feature, the publish retain flag.
## MQTT Retain
In the MQTT protocol, setting the `retain` flag on a published message asks the MQTT broker (server) to store that message. Then any new clients which connect and subscribe to that topic will immediately receive the retained message. Retain makes writing basic MQTT-only Internet of Things clients easier, without it, a client that connects and subscribes to a feed topic has to wait until a new value is published on the feed to know what state it should be in. In the case of slowly updated feeds, there could be hours between updates which means a device that disconnects and reconnects (for example, due to power cycling or sleeping) might lose the current value for a long time between updates.
## Adafruit IO's Limitations
Among other factors, our scale, Adafruit IO's mix of MQTT & HTTP APIs, the speed at which were taking in new data, and the fact that were already storing almost every message that is sent mean that a “simple” feature like retain becomes difficult to support without making MQTT service performance worse for everyone.
Since we dont actually store data in the broker but at a lower level and cant support PUBLISH retain directly, were proposing a different solution for the retaining problem: the `/get` topic modifier.
## Using the */get topic
For any given Adafruit IO MQTT feed or group, subscribe to the appropriate topic using the feed or group **key**, then add `/get` to the topic you subscribed to and publish anything to that new topic (our Arduino library uses the null character: `\0`). IO will immediately publish, just for that client, the most recent value received on the feed.
For example, let's imagine we have a device that subscribes to a counter feed: `uname/f/counter`. If we want to get the latest value, the `/get` topic we should publish to is `uname/f/counter/get`. After connecting to IO, subscribing to `uname/f/counter`, and publishing ` ` to `uname/f/counter/get`, we will immediately receive a message on our `uname/f/counter` subscription with the last value that was published to `counter`.
If youre using the Adafruit IO Arduino library, you can add `/get` support to your project using the following code snippet:
```
// ... from the adafruitio_01_subscribe example sketch
AdafruitIO_Feed *counter = io.feed("counter");
void setup() {
// 1. start IO connection
io.connect();
// 2. prepare MQTT subscription with handler function
counter->onMessage(handleMessage);
// 3. wait for successful connection
while(io.mqttStatus() < AIO_CONNECTED) {
delay(500);
}
// 4. send /get message, requesting last value, triggering
// the handleMessage handler function
counter->get(); // ask Adafruit IO to resend the last value
}
```
You can also perform a `/get` using the Adafruit IO CircuitPython library in one line of code:
<% partial 'helpers/inline_code' do %>
```python
io.get('temperature')
```
<% end %>

View file

@ -1,157 +0,0 @@
# MQTT Data Format
There are a few ways to send data to our MQTT API if you're writing your own client library.
The simplest way to send values to an IO Feed topic is to just send the value. For example, a temperature sensor is going to produce numeric values like `22.587`. If you're sending to `mosfet/feeds/photocell-one` you can use the raw number or a string. That means either `22.587` or `22.587` will be accepted as a numeric value. Adafruit IO does its best to treat data as numeric values so that we can show you your data as a chart on an Adafruit IO dashboard and through our [Charting API](https://io.adafruit.com/api/docs/#!/Data/chartData).
## Sending data with location
To tag your data with a location value, you'll either need to wrap it in a JSON object first or send it to the special `/csv` formatted MQTT topic.
## Sending JSON
JSON can be sent to either the base topic or the /json topic - for example `mosfet/feeds/photocell-one` or `mosfet/feeds/photocell-one/json`.
The proper format for location tagged JSON data is:
Example JSON topic object:
<% partial 'helpers/inline_code' do %>
```javascript
{
"value": 22.587,
"lat": 38.1123,
"lon": -91.2325,
"ele": 112
}
```
<% end %>
Specifically, JSON objects must include a `value` key, and may include `lat`, `lon`, and `ele` keys.
## Sending CSV
Alternatively, you can send location tagged data to `/csv` topics. In this example, that would be the topic `mosfet/feeds/photocell-one/csv` instead of `mosfet/feeds/photocell-one`. Both store data in the same feed. The format IO expects for location tagged CSV data is VALUE, LATITUDE, LONGITUDE, ELEVATION.
With the example data shown before, that means you could publish the string `"22.587,38.1123,-91.2325,112"` to `mosfet/feeds/photocell-one/csv`. to store the value `"22.587"` in the location `latitude: 38.1123`, `longitude: -91.2325`, `elevation: 112`.
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.
<% partial 'helpers/inline_code' do %>
```ruby
# first you'll need https://github.com/njh/ruby-mqtt
require 'mqtt'
username = 'test_username'
key = 'not-a-real-key'
url = "mqtts://#{ username }:#{ key }@io.adafruit.com"
mqtt_client = MQTT::Client.connect(url, 8883)
# simplest thing that could possibly work
mqtt_client.publish('test_username/feeds/example', 22.587)
# sending numbers as strings is fine, IO stores all data internally
# as strings anyways
mqtt_client.publish('test_username/feeds/example', '22.587')
# CSV formatted, no location
mqtt_client.publish('test_username/feeds/example/csv', '22.587')
# CSV formatted, with location
mqtt_client.publish('test_username/feeds/example/csv',
'22.587,38.1123,-91.2325,112')
# JSON formatted, no location
mqtt_client.publish('test_username/feeds/example', '{"value":22.587}')
mqtt_client.publish('test_username/feeds/example/json', '{"value":22.587}')
# JSON formatted, with location
mqtt_client.publish('test_username/feeds/example',
'{"value":22.587,"lat":38.1123,"lon":-91.2325,"ele":112}')
mqtt_client.publish('test_username/feeds/example/json',
'{"value":22.587,"lat":38.1123,"lon":-91.2325,"ele":112}')
```
<% end %>
## Sending JSON Data through Adafruit IO
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.
JSON Response Format Example
<% partial 'helpers/inline_code' do %>
```javascript
{
"value": 22.587,
"lat": 38.1123,
"lon": -91.2325,
"ele": 112
}
```
<% end %>
This lets us store the individual value, `22.587`, and data about the value: its latitude, longitude, and elevation. Metadata!
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.
### IO-Formatted JSON
The simplest way to send JSON data to Adafruit IO is to wrap it in the format described above. For example, if instead of `22.587`, I wanted to send something like, `{"sensor-1":22.587,"sensor-2":13.182}`, the "wrapped" version would look like this:
Example of IO-Formatted JSON
<% partial 'helpers/inline_code' do %>
```javascript
{
"value": {"sensor-1":22.587,"sensor-2":13.182},
"lat": 38.1123,
"lon": -91.2325,
"ele": 112
}
```
<% end %>
It'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.
### Double-Encoded JSON Strings
The second way you can send JSON data as a value is to "double encode" it before sending, in which case IO will treat it as a raw string.
If you're using something like javascript's `JSON.stringify` function or Ruby's `JSON.generate`, double encoding means passing the result of
`JSON.stringify` through `JSON.stringify` a second time. In this node.js console example, you can see the difference:
Here's an example of sending double-encoded strings through Adafruit IO:
<% partial 'helpers/inline_code' do %>
```javascript
> JSON.stringify({"sensor-1":22.587,"sensor-2":13.182})
'{"sensor-1":22.587,"sensor-2":13.182}'
> JSON.stringify(JSON.stringify({"sensor-1":22.587,"sensor-2":13.182}))
'"{\"sensor-1\":22.587,\"sensor-2\":13.182}"'
```
<% end %>
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.
Here's an example of interpreting double-encoded JSON Strings sent through Adafruit IO:
<% partial 'helpers/inline_code' do %>
```javascript
> var input = '"{\\\"sensor-1\\\":22.587,\\\"sensor-2\\\":13.182}"'
> JSON.parse(JSON.parse(input))
{ 'sensor-1': 22.587, 'sensor-2': 13.182 }
```
<% end %>
### Non-IO Formatted JSON
The third way you can send raw JSON data is to just send it. If Adafruit IO doesn't find a "value" 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 `{"sensor-1":22.587,"sensor-2":13.182}` will result in `{"sensor-1":22.587,"sensor-2":13.182}` being stored in IO and sent
to MQTT subscribers.

View file

@ -1,104 +0,0 @@
# Group Topics
You aren't limited to just Feed based MQTT topics, Adafruit IO supports grouped feeds as well. [Similar to our HTTP group data creation API](https://io.adafruit.com/api/docs/#operation/createGroupData), you can publish to multiple feeds or subscribe to multiple feeds through a single MQTT topic.
The topics formats for publishing or subscribing are:
- `(username)/groups/(group name or key)`
- `(username)/groups/(group name or key)/json`
- `(username)/groups/(group name or key)/csv`
### Publish to Feeds in a Group
If you use the `/json` or `/csv` endings on your group MQTT topic, your data should be formatted in JSON or CSV, respectively. By default, IO expects published values to be in JSON format.
The JSON and CSV format IO expects are displayed below:
JSON Expected Response from Adafruit IO
<% partial 'helpers/inline_code' do %>
```json
{
"feeds": {
"key-1": "value 1",
"key-2": "value 2",
"key-3": "value 3"
},
"location": {
"lat": 0.0,
"lon": 0.0,
"ele": 0.0
}
}
```
<% end %>
CSV Format Expected Response from Adafruit IO
<% partial 'helpers/inline_code' do %>
```csv
key-1,value 1
key-2,value 2
key-3,value 3
location,0.0,0.0,0.0
```
<% end %>
## Group Guidelines
- In each payload format, `key-1` represents the respective feed's key and `value 1` represents the value you'd like to publish to that feed.
- For CSV location values, the location is interpreted as `lat`, `lon`, `ele` and `ele` is optional `/` not required.
- Any number of feeds present in the group may be included.
- Each value may be either a string or a number.
- If any feed key is included that does not already belong to a feed in the group, then a new feed with the given key as its name will be created.
### Subscribing to groups
If you use the `/json` or `/csv` endings when subscribing to your group MQTT topic, your data will be formatted in JSON or CSV, respectively. By default, IO publishes values in JSON format.
The formats your subscription will receive are the same as the formats IO expects to receive. Expected responses for JSON and CSV are below.
Expected Group JSON Response
<% partial 'helpers/inline_code' do %>
```json
{
"feeds": {
"key-1": "value 1",
"key-2": "value 2",
"key-3": "value 3"
},
"location": {
"lat": 1.0,
"lon": 2.0,
"ele": 3.0
}
}
```
<% end %>
Expected Group CSV Response
<% partial 'helpers/inline_code' do %>
```csv
key-1,value 1
key-2,value 2
key-3,value 3
location,1.0,2.0,3.0
```
<% end %>
It's important to note that you will only receive updated values for the feeds that received new values. That means if you're subscribed to `{username}/groups/example` and publish to `{username}/feeds/key-1`, the subscription will receive:
<% partial 'helpers/inline_code' do %>
```json
{
"feeds": {
"key-1": "value 1"
}
}
```
<% end %>
It's also worth noting that JSON subscription formats will always receive string type values, regardless of whether a string or number was published.

View file

@ -1,45 +0,0 @@
# Adafruit IO MQTT API
[MQTT](http://mqtt.org/), or message queue telemetry transport, is a protocol for device communication that Adafruit IO supports. Using a MQTT library or client you can publish and subscribe to a feed to send and receive feed data.
If you aren't familiar with MQTT check out this [introduction from the HiveMQ blog](http://www.hivemq.com/mqtt-essentials-part-1-introducing-mqtt/).
All of the subsequent posts in the [MQTT essentials series](http://www.hivemq.com/mqtt-essentials-wrap-up/) are great and worth reading too.
## Client Libraries
To use the MQTT API that Adafruit IO exposes you'll need a MQTT client library. For Python, Ruby, and Arduino you can use Adafruit's
IO libraries as they include support for MQTT. For other languages or platforms look for a MQTT library that ideally supports the MQTT 3.1.1 protocol.
* **Arduino**: [Adafruit MQTT](https://github.com/adafruit/Adafruit_MQTT_Library)
* **Python**: [Adafruit IO Python](https://github.com/adafruit/Adafruit_IO_Python) includes an MQTT Client.
* **CircuitPython**: [Adafruit IO CircuitPython](https://github.com/adafruit/Adafruit_CircuitPython_AdafruitIO/) includes a MQTT Client class, `IO_MQTT`.
* **MicroPython**: MicroPython devices can connect to Adafruit IO using [uMQTT](https://github.com/micropython/micropython-lib/tree/master/umqtt.simple)
* **Ruby**: [Adafruit IO Ruby](https://github.com/adafruit/io-client-ruby) includes an MQTT client.
## MQTT Connection Details
We *strongly* recommend connecting using SSL (Port 8883) if your client allows it. Port 443 is for MQTT-over-Websockets
clients which generally run in browsers, like Eclipse Paho, HiveMQ Websockets, or MQTTJS.
| | |
|----------------------|---------------------------|
| **Host** | io.adafruit.com |
| **Secure (SSL) Port**| 8883 |
| **Insecure Port** | 1883 |
| **MQTT over Websocket| 443 |
| **Username** | Your Adafruit IO Username |
| **Password** | Your Adafruit IO Key |
_Need to manually set a Client ID for your MQTT client?_ Use a unique value such as a [random GUID](https://www.guidgenerator.com/online-guid-generator.aspx). Whenever possible, leave the client ID field blank.
<aside class="notice">
Connecting to Adafruit IO via MQTT and reusing the client ID of an existing connection will result in <strong>immediate disconnection</strong> of the other MQTT client. The MQTT specification requires that "each client connecting to the server has a unique ClientId." <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/csprd02/mqtt-v3.1.1-csprd02.html#_Toc385349767">link</a>
</aside>
We do not currently limit the number of clients that can connect to Adafruit IO, but we do limit the rate at which connections may be attempted to 20 per minute. Exceeding the connection attempt rate limit will result in a temporary ban.

View file

@ -1,10 +0,0 @@
# MQTT QoS
One feature of MQTT is the ability to specify a QoS, or quality of service, level when publishing feed data. This allows an application to confirm that its data has been sucessfully published.
If you aren't familiar with MQTT QoS levels [be sure to read this great blog post](http://www.hivemq.com/mqtt-essentials-part-6-mqtt-quality-of-service-levels/) explaining their meaning.
For publishing feed values **the Adafruit IO MQTT API supports QoS level 0 (at most once) and 1 (at least once) only**.
QoS level 2 (exactly once) is _not_ currently supported.

View file

@ -1,44 +0,0 @@
# MQTT Topics
## Feed Topic Format
Adafruit IO's MQTT API exposes feed data using special topics. You can publish a new value for a feed to its topic, or you
can subscribe to a feed's topic to be notified when the feed has a new value.
* `{your Adafruit IO username}/feeds/{feed key}`
* `{your Adafruit IO username}/feeds/{feed key}/csv`
* `{your Adafruit IO username}/feeds/{feed key}/json`
## Group Topic Format
* `{your Adafruit IO username}/groups/{group key}`
* `{your Adafruit IO username}/groups/{group key}/csv`
* `{your Adafruit IO username}/groups/{group key}/json`
## Small Topic Format
If you're using an embedded system and need to conserve space, use the `/f/` or `/g/` topic formats:
* `{your Adafruit IO username}/g/{group key}`
* `{your Adafruit IO username}/g/{group key}/csv`
* `{your Adafruit IO username}/g/{group key}/json`
* `{your Adafruit IO username}/f/{feed key}`
* `{your Adafruit IO username}/f/{feed key}/csv`
* `{your Adafruit IO username}/f/{feed key}/json`
## Using a Wildcard
You can also subscribe to the parent 'feeds' path to be notified when any owned feed changes using MQTT's `#` wildcard character. For example, the user could subscribe to either:
* `{your Adafruit IO username}/feeds/#`
* `{your Adafruit IO username}/f/#`
Once subscribed to the path above any change to a feed owned by `Your_Adafruit_IO_Username` will be sent to the MQTT client. The topic will specify the feed that was updated, and the payload will have the new value.
**Be aware the MQTT server sends feed updates on all possible paths for a specific feed**. For example, subscribing to `IO-Username/f/#` and publishing to `IO-Username/f/photocell-one` would produce messages from: `IO-Username/f/photocell-one`, `IO-Username/f/photocell-one/json`, and `IO-Username/f/photocell-one/csv`; each referring to the same updated value. To reduce noise, _make sure to grab the specific topic_ of the feed `/` format you're interested in and change your subscription to that.
If you'd like to avoid the formatted feeds (`/json` and `/csv` topics) _but still see all the feeds you're publishing to_, you can use MQTT's `+` wildcard in place of `#`. In this case, subscribing to `IO-Username/f/+` would produce output on `IO-Username/f/photocell-one`, but _not_ `IO-Username/f/photocell-one/json`.

View file

@ -1,11 +0,0 @@
# Randomizer Topics
Create random data streams that can generate colors, words, numbers, or pick a value from a custom data set and send it directly to your devices.
Prior to subcribing to the randomizer topic, you need to [generate the topics](https://io.adafruit.com/services/words) to get the id.
## Subscribe to the Generated Topic
* `{username}/integrations/words/{generated topic id}`
MQTT random word subscriptions will publish data once per minute to every client that is subscribed to the same topic.

View file

@ -1,29 +0,0 @@
# MQTT API Rate Limiting
Adafruit IO's MQTT server imposes a rate limit to prevent excessive load on the service. If a user performs too many **publish** actions in a short period of time then some of the requests will be rejected and an error message will be published on [your /throttle topic](#error-topics). The current rate limit is at most 30 requests per minute for free accounts, 60 per minute with an IO+ account, and expandable via Adafruit IO+ Boost applied to your account.
We also limit a few other actions on Adafruit IO's MQTT broker. If you send, within a minute, more than: 100 MQTT SUBSCRIBE requests, 10 _failed_ MQTT SUBSCRIBE requests, or 10 _failed_ MQTT PUBLISH requests; or you send enough messages after passing the rate limit; or you attempt to log in more than 20 times within a minute, your account will be temporarily banned from the MQTT broker.
Most of the systems connecting to Adafruit IO are simple, automated devices and MQTT client scripts. A runaway ESP8266 sending MQTT SUBSCRIBE packets inside the main `loop()` function of an Arduino sketch can send about 500 packets per minute. It wouldn't take many poorly written clients connecting to our MQTT broker to crash the service for everyone if we didn't add rate limits to every action.
If you exceed a rate limit, a notice will be sent to the `(username)/throttle` topic. If your account is temporarily banned, a notice will be sent to the `{username}/errors` topic. While developing your project, you should always keep subscriptions to the error topics open so you can see when you're getting close to the Adafruit IO rate limits and when you've been blocked.
This limit applies to all connections so if you have multiple devices or clients publishing data be sure to delay their updates enough that the total rate is below 2 requests/second.
## Rate Limit Bans
Temporary MQTT bans start at 30 seconds and scale as a multiple of the number of bans within the last hour up to one hour maximum. For example, 10 rejected MQTT SUBSCRIBE requests will trigger a temporary ban of 30 seconds, that's 1 ban. If it's a device that automatically wakes up, connects to Adafruit IO, and sends a stream of rejected SUBSCRIBE packets, it will be banned again. The second ban results in 60 seconds offline, the third is 90 seconds, and so on.
You can visit your Adafruit IO monitor page any time
## Preventing MQTT Bans
A misbehaving MQTT device--for example, a device configured for a different MQTT broker like Home Assistant--that attempts to publish to invalid Adafruit IO MQTT topics can lock _every_ device and browser session out of your Adafruit IO MQTT account for an hour at a time.
The easiest way to prevent a temporary or permanent MQTT block being put against your account is to delay how frequently your MQTT client sends messages.
The second thing to check is that you are not using a different Internet of Things software toolkit to talk to Adafruit IO. The Adafruit IO MQTT broker

View file

@ -1,39 +0,0 @@
# Time Topics
Adafruit IO provides some built-in MQTT topics for getting the current server time. The current available topics are:
* `time/seconds`
* `time/millis`
* `time/ISO-8601`
* `time/hours`
Most of the Adafruit IO client libraries provide helper functions for easy use of these topics:
* [Arduino](https://github.com/adafruit/Adafruit_IO_Arduino/blob/master/examples/adafruitio_17_time_subscribe/adafruitio_17_time_subscribe.ino)
* [Python](https://github.com/adafruit/Adafruit_IO_Python/blob/master/examples/mqtt/mqtt_time.py)
* [CircuitPython](https://github.com/adafruit/Adafruit_CircuitPython_AdafruitIO/blob/master/examples/adafruit_io_mqtt/adafruit_io_time.py)
## time/seconds
This topic publishes the current time in [Unix epoch seconds](https://en.wikipedia.org/wiki/Unix_time).
The current Unix epoch time at the time of writing is: `1562164754`.
## time/millis
This topic publishes the same thing as time/seconds every second, but with slightly higher precision and more digits.
The current Unix epoch time in milliseconds at the time of writing is: `1562165081839`
## time/ISO-8601
This topic publishes the current time in [ISO 8601 UTC format](https://en.wikipedia.org/wiki/ISO_8601). That's `year-month-dayThour:minute:second.millisecondsZ` where "-", ":", "T", and "Z" are character literals / always included in the time string.
The current time in ISO 8601 UTC format at the time of writing is: `2019-07-03T14:47:16.038Z`
## time/hours
This topic publishes the current hour of the day in 24 hour format (the values 0 - 23) in the UTC time zone. It only publishes once every hour.

View file

@ -1,79 +0,0 @@
# Troubleshooting
What can you do when something is going wrong with your project? Adafruit IO provides a few ways for you to find out what's happening behind the scenes with your MQTT connected devices.
## Understanding Error Messages
The two [MQTT error topics](#error-topics) produce alerts, warnings, and error messages when there's a problem with your MQTT data. MQTT error messages are **not stored permanently**, so if you want to see them you'll need to keep the monitor page open while developing your project.
We try to be descriptive enough that you can figure out what went wrong, but there are a few categories of error messages you may run into. We list an example message for each category of error, yours will look different but most are in the form:
`CLIENT_ID IP_ADDRESS MQTT_ACTION MQTT_TOPIC ...message`
### Exceeded Rate Limit
On `{username}/throttle`:
When MQTT packets are arriving too quickly (SUBSCRIBE only, warning):
<%= error_message 'io-badstuff-23111 172.18.0.1 SUBSCRIBE time/seconds only 5 attempts remaining in the next 60 seconds, please slow your request rate' %>
When publishing data too quickly (warning): <%= error_message 'test_username data rate limit reached, 21 seconds until throttle released' %>
On `{username}/errors`:
When MQTT packets are arriving too quickly (SUBSCRIBE only, error): <%= error_message 'io-badstuff-23111 172.18.0.1 SUBSCRIBE time/seconds made too many requests, wait before reconnecting' %>
After a certain number of throttle warning messages have been sent: <%= error_message 'enforcement limit reached, your account is banned for 30 seconds' %>
### Invalid MQTT topic
There are several variations of invalid MQTT topic errors. All error messages will be published on the `{username}/errors` topic.
When making a PUBLISH or SUBSCRIBE request for an MQTT topic not recognized by Adafruit IO: <%= error_message 'io-badstuff-12558 172.18.0.1 SUBSCRIBE LWT/$SYS/obe/pixel/adafruit.server/sessions-005 rejected, not a valid resource topic' %>
Sometimes invalid MQTT topics or topics that don't fit the `{username}/{type}/{key}/{format}` pattern can look like a different error to IO. The most common is seeing an error message like this when PUBLISHING: <%= error_message 'io-mqtt-149edf5e 172.18.0.1 PUBLISH ,,21,9,,,33,, OK -72.223332,12.100,0.17,28.1,1,, rejected, only shared feeds may be published to' %>
Or: <%= error_message 'io-mqtt-149edf5e 172.18.0.1 PUBLISH rejected, only shared feeds may be published to' %>
In each case, IO is showing the topic your code specified in between "PUBLISH" and "rejected." In the first example, the given topic was `,,21,9,,,33,, OK -72.223332,12.100,0.17,28.1,1,,` and in the second example, the given topic was an empty string, ` `. Both examples probably mean there was an error in the sketch that caused the MQTT topic to become corrupted in memory before publishing data.
A good idea if you're getting _any_ error messages when publishing or subscribing from a new sketch is to print out the MQTT topic you're using to the serial console (`Serial.println` in Arduino, `print()` in CircuitPython) in your sketch before you publish or subscribe just to make sure the data you're sending is the data you think you're sending.
The meaning of the error message, "rejected, only shared feeds may be published to", is that IO saw a username other than the one you authenticated with in the `{username}` part of an MQTT topic and something other than "feeds" or "f" in the `{type}` part of an MQTT topic. Because the topic part of the MQTT packet IO received was, `,,21,9,,,33,, OK -72.223332,12.100,0.17,28.1,1,,` IO couldn't find a username or a type in the string, so it had to reject the PUBLISH message.
### MQTT action flood
On `{username}/errors`:
When subscribing or publishing to resources faster than IO can verify that you have permission to access them: <%= error_message 'io-badstuff-94864 172.18.0.1 SUBSCRIBE time/seconds request flood, disconnecting' %>
### Resource not available
On `{username}/errors`:
When you don't have permission to access a shared resource: <%= error_message 'io-badstuff-29349 172.18.0.1 SUBSCRIBE other_username/feeds/something.fake-11 rejected, resource not available or not authorized' %>
### Action attempted while banned
On `{username}/errors`:
When attempting to publish or subscribe after your account has been temporarily banned: <%= error_message 'io-mqtt-0d63acfb 172.18.0.1 PUBLISH test_username/feeds/example.counter-3 rejected, user is temporarily blocked' %>
## Writing Safe MQTT Code
**Always. Use. Delay.** Make sure there is time in between messages to the Adafruit IO MQTT broker. If you're saving data in an Arduino or CircuitPython sketch inside the program's main loop, make sure you're delaying, sleeping, or using some other technique to put space in between messages.
**Use current libraries.** Adafruit provides complete API client libraries for Arduino, Python, Ruby, and Javascript. When in doubt, use our code to build your next project.
**Use the least data possible.** It is always better to send data from a sensor infrequently and slowly increase the frequency as needed rather than sending as quickly as possible from the beginning. An old device or project that you forgot about can easily take down your whole account when you go to add something new. Also, when dealing with sensors like temperature, outdoor light level, or wind speed, reality doesn't change very fast so there's no need for your data to change fast either.
**Never reuse Internet of Things projects from other systems without making sure it conforms to Adafruit IO's requirements**. Code that works with Home Assistant, Node Red, or any other open source MQTT broker is likely to use MQTT topic conventions that _will not work_ with Adafruit IO. Plugging Adafruit IO's broker credentials into an example project from another system is a quick way to get your account locked by a runaway process.
**Ask questions on the forums or Discord!** There's a community of people who may have already run into the same problem you're having. Search the forums, ask a question, stop by and see what people are working on. Whatever approach you take, you being involved in the Adafruit community can make the difference for someone else. You can find the forums here: [https://forums.adafruit.com/viewforum.php?f=56](https://forums.adafruit.com/viewforum.php?f=56) and sign up for Adafruit's Discord chat server here: [https://discord.gg/adafruit](https://discord.gg/adafruit)

View file

@ -1,26 +0,0 @@
# Weather Topics (IO+)
With access to weather data powered by Dark Sky, you can get hyper-local forecasts sent directly to your devices. Weather data is updated at most once every 20 minutes.
When you have an IO Plus account, you can track the weather through our HTTP or MQTT APIs for up to 5 locations at a time.
Prior to subscribing to the weather topic, you'll need to [generate the topics](https://io.adafruit.com/services/weather) to get the id.
## Subscribe to the Generated Topic
* `{username}/integration/weather/{id}/{type}`
Where :id is the ID of the weather record you want data for and :type is the kind of forecast data you want. Valid types are:
* current
* forecast_minutes_5
* forecast_minutes_30
* forecast_hours_1
* forecast_hours_2
* forecast_hours_6
* forecast_hours_24
* forecast_days_1
* forecast_days_2
* forecast_days_5
MQTT weather subscriptions will publish updated data once per minute to every client that is subscribed to a valid topic.

View file

@ -1,48 +0,0 @@
---
title: Adafruit IO API Reference
language_tabs:
- shell: CURL
- cpp: Arduino
- python: Python
- python: Circuitpython
- ruby: Ruby
toc_footers:
- <a href='http://io.adafruit.com'>Adafruit IO</a>
- <a href='https://io.adafruit.com/blog'>Adafruit IO News</a>
- <a href='https://io.adafruit.com/plus'>Adafruit IO Plus</a>
- <a href='https://io.adafruit.com/terms'>Adafruit IO ToS</a>
- <a href='https://io.adafruit.com/feedback'>Submit Feedback</a>
toc_append:
- href: mqtt
text: Adafruit IO MQTT API
- href: cookbook
text: API Cookbook
includes:
- introduction
- authentication.md.erb
- client_libraries.md.erb
- rate_limiting
- http/pagination
- http/data.md.erb
- http/feeds.md.erb
- http/groups.md.erb
- http/webhooks.md.erb
- http/actions.md.erb
- http/activities.md.erb
- http/blocks.md.erb
- http/dashboards.md.erb
- http/permissions.md.erb
- http/users.md.erb
- http/tokens.md.erb
- http/services.md.erb
- errors
search: true
---

View file

@ -1,2 +0,0 @@
//= require ./all_nosearch
//= require ./app/_search

View file

@ -1,16 +0,0 @@
//= require ./lib/_energize
//= require ./app/_toc
//= require ./app/_lang
$(function() {
loadToc($('#toc'), '.toc-link', '.toc-list-h2', 10);
setupLanguages($('body').data('languages'));
$('.content').imagesLoaded( function() {
window.recacheHeights();
window.refreshToc();
});
});
window.onpopstate = function() {
activateLanguage(getLanguageFromQueryString());
};

View file

@ -1,164 +0,0 @@
//= require ../lib/_jquery
/*
Copyright 2008-2013 Concur Technologies, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
*/
;(function () {
'use strict';
var languages = [];
window.setupLanguages = setupLanguages;
window.activateLanguage = activateLanguage;
window.getLanguageFromQueryString = getLanguageFromQueryString;
function activateLanguage(language) {
if (!language) return;
if (language === "") return;
$(".lang-selector a").removeClass('active');
$(".lang-selector a[data-language-name='" + language + "']").addClass('active');
for (var i=0; i < languages.length; i++) {
$(".highlight.tab-" + languages[i]).hide();
$(".lang-specific." + languages[i]).hide();
}
$(".highlight.tab-" + language).show();
$(".lang-specific." + language).show();
window.recacheHeights();
// scroll to the new location of the position
if ($(window.location.hash).get(0)) {
$(window.location.hash).get(0).scrollIntoView(true);
}
}
// parseURL and stringifyURL are from https://github.com/sindresorhus/query-string
// MIT licensed
// https://github.com/sindresorhus/query-string/blob/7bee64c16f2da1a326579e96977b9227bf6da9e6/license
function parseURL(str) {
if (typeof str !== 'string') {
return {};
}
str = str.trim().replace(/^(\?|#|&)/, '');
if (!str) {
return {};
}
return str.split('&').reduce(function (ret, param) {
var parts = param.replace(/\+/g, ' ').split('=');
var key = parts[0];
var val = parts[1];
key = decodeURIComponent(key);
// missing `=` should be `null`:
// http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
val = val === undefined ? null : decodeURIComponent(val);
if (!ret.hasOwnProperty(key)) {
ret[key] = val;
} else if (Array.isArray(ret[key])) {
ret[key].push(val);
} else {
ret[key] = [ret[key], val];
}
return ret;
}, {});
};
function stringifyURL(obj) {
return obj ? Object.keys(obj).sort().map(function (key) {
var val = obj[key];
if (Array.isArray(val)) {
return val.sort().map(function (val2) {
return encodeURIComponent(key) + '=' + encodeURIComponent(val2);
}).join('&');
}
return encodeURIComponent(key) + '=' + encodeURIComponent(val);
}).join('&') : '';
};
// gets the language set in the query string
function getLanguageFromQueryString() {
if (location.search.length >= 1) {
var language = parseURL(location.search).language;
if (language) {
return language;
} else if (jQuery.inArray(location.search.substr(1), languages) != -1) {
return location.search.substr(1);
}
}
return false;
}
// returns a new query string with the new language in it
function generateNewQueryString(language) {
var url = parseURL(location.search);
if (url.language) {
url.language = language;
return stringifyURL(url);
}
return language;
}
// if a button is clicked, add the state to the history
function pushURL(language) {
if (!history) { return; }
var hash = window.location.hash;
if (hash) {
hash = hash.replace(/^#+/, '');
}
history.pushState({}, '', '?' + generateNewQueryString(language) + '#' + hash);
// save language as next default
localStorage.setItem("language", language);
}
function setupLanguages(l) {
var defaultLanguage = localStorage.getItem("language");
languages = l;
var presetLanguage = getLanguageFromQueryString();
if (presetLanguage) {
// the language is in the URL, so use that language!
activateLanguage(presetLanguage);
localStorage.setItem("language", presetLanguage);
} else if ((defaultLanguage !== null) && (jQuery.inArray(defaultLanguage, languages) != -1)) {
// the language was the last selected one saved in localstorage, so use that language!
activateLanguage(defaultLanguage);
} else {
// no language selected, so use the default
activateLanguage(languages[0]);
}
}
// if we click on a language tab, activate that language
$(function() {
$(".lang-selector a").on("click", function() {
var language = $(this).data("language-name");
pushURL(language);
activateLanguage(language);
return false;
});
});
})();

Some files were not shown because too many files have changed in this diff Show more