# How to use Blockly for Actions on Adafruit IO

## Overview

Info: Blockly on Adafruit IO is still under active development. New plugins, and features may be added or removed rapidly. Let us know in the forums if you have any Blockly wishes / favorite plugins you think would be well suited to Adafruit. 

Please let us know (via [io.adafruit.com/support](https://io.adafruit.com/support)) if you miss a feature we've removed, can't do what you used to be able to, or find something broken! Announcements for new features, etc. are usually on the Adafruit Blog.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/895/medium800/community_support_Screenshot_2024-02-21_154517.png?1708547200)

While you can build just about any kind of IoT device or project with Adafruit IO's [feed](https://learn.adafruit.com/adafruit-io-basics-feeds) [dashboard](https://learn.adafruit.com/adafruit-io-basics-dashboards) functionality, you can add a little more logic and integration using [Actions](https://learn.adafruit.com/all-the-internet-of-things-episode-four-adafruit-io/triggers). In Adafruit IO, Actions are a way to do something when a certain situation occurs. **We've built a custom Blockly App to allow easy creation and editing of [Actions](https://io.adafruit.com/actions) on Adafruit IO.**

Whether you've used Actions before or not, this guide will get you up to speed using Blockly Actions to power up your Adafruit IO Project!

## What is Blockly?
![Blockly example image from https://developers.google.com/blockly](https://cdn-learn.adafruit.com/assets/assets/000/127/883/medium800/community_support_Screenshot_2024-02-21_170033.png?1708535058 Blockly workspace example showing a do-while loop, from https://developers.google.com/blockly)

Blockly is an [open-source project](https://developers.google.com/blockly/guides/get-started/what-is-blockly) maintained by Google. It's a block-based code-editor, or in other words a tool for diagrammatic representation of code, designed to be easy to use for beginners and experts alike!

The editor uses puzzle-piece like blocks to represent code concepts like variables, logical expressions, loops, and more. It lets users program without having to worry about syntax or the intimidation of the command line.

## What are Actions?
![](https://cdn-learn.adafruit.com/assets/assets/000/128/160/medium800/community_support_Screenshot_2024-02-21_172331.png?1760890116 Legacy Adafruit IO Actions - Choose a single trigger between Reactive, Scheduled, or Timed (Reactive + Delay))

While you can build just about any kind of IoT device or project with Adafruit IO's [feed](https://learn.adafruit.com/adafruit-io-basics-feeds) and [dashboard](https://learn.adafruit.com/adafruit-io-basics-dashboards) functionality, you can add a little more logic and integration using [Actions](https://learn.adafruit.com/all-the-internet-of-things-episode-four-adafruit-io/triggers).

## I know how to use Adafruit IO Actions, how are the Blockly Actions different?
As our new use of Blockly grows, we plan to add all sorts of exciting features, like maths functions, logical operators, and other useful extensions for parsing data. However, for the initial release, we've concentrated on replicating the functionality of the existing Action forms.

In the past, we had 3 types of [Actions](https://learn.adafruit.com/all-the-internet-of-things-episode-four-adafruit-io/triggers) (or Triggers) supported:

1. **Reactive Action** - Every time a feed is updated this action is _immediately_ executed and its conditional expression is checked (if a feed value matches the desired condition).  
  
2. **Timed Action** - This is very similar to reactive actions, as they are triggered based on a new feed value, _but only executed_ _after a set delay._  
  
3. **Scheduled Action** &nbsp;- The traditional timer or scheduling trigger, where you specify a set of times/days/dates when the action should run.

Each one was configured using an old input form, which was fine for simple use cases, but sometimes required a bit of guesswork as to how it functioned. This was especially true for the scheduling triggers.

Here we see a simple "Reactive Action" example, showing that if a value of `1` is sent to the `toast_burnt` feed, then the reactive action will fire the value `1` to the `disable_me` feed, effectively being used to disable power to my toaster.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/889/medium800/community_support_Screenshot_2024-02-21_173020.png?1708536922 Older form for a Reactive Action)

The main improvements you'll see today using Blockly are that we have greatly enhanced the usability, with most use cases now covered, and supplemented the help information available when editing your actions (menus and mouse-over tooltips).

![](https://cdn-learn.adafruit.com/assets/assets/000/127/892/medium800/community_support_Screenshot_2024-02-21_202230.png?1708546987 Newer Blockly workspace showing the same Action and a tooltip for the Reactive Trigger block)

Info: 

The next page looks at the sections of the user-interface, what each thing is named (which is useful to know when asking / searching for help), and how to use each "thing".

# How to use Blockly for Actions on Adafruit IO

## Using Blockly

Let's start at the basics, what [everything is called](https://developers.google.com/blockly/guides/get-started/workspace-anatomy), follow that link to the visual glossary for Blockly. Alternatively we'll cover the essentials here.

## The Workspace
![](https://cdn-learn.adafruit.com/assets/assets/000/128/164/medium800/community_support_Screenshot_2024-02-21_205451.png?1709062151)

First off, the Blockly area of the browser window is called a&nbsp; **workspace** , the Blockly workspace.   
  
When you create a new action, you'll start with just the root block on the workspace, called the Action Root block, or just root block.

Notice the blue triangular exclamation-mark icon on the root block. It shows there is a problem with the block, and clicking it will tell you more.

![community_support_Screenshot_2024-02-27_192133.png](https://cdn-learn.adafruit.com/assets/assets/000/128/165/medium640/community_support_Screenshot_2024-02-27_192133.png?1709062231)

In this case, it's telling you the root block must have a&nbsp; **Trigger block** , and also an&nbsp; **Action block** before it is complete.

Lastly in the bottom right of the workspace are the Zoom and Trashcan controls. The top option zooms to fit all blocks in view. The crosshairs with a dot inside resets the view to default zoom, and the plus and minus zoom in and out.

![community_support_Screenshot_2024-02-27_192200.png](https://cdn-learn.adafruit.com/assets/assets/000/128/170/medium640/community_support_Screenshot_2024-02-27_192200.png?1709062380)

Next the grey panel to the left side of the workspace is called the **Category**  **Toolbox.**

When you click on a category, a flyout **toolbox** menu appears. The **toolbox** contains all the **blocks** in that category.

Each block has a brief description, hovering your mouse pointer over a block will bring up a helpful note for using the block.

![community_support_Screenshot_2024-02-21_210916.png](https://cdn-learn.adafruit.com/assets/assets/000/127/900/medium640/community_support_Screenshot_2024-02-21_210916.png?1708549802)

### Moving Blocks in the Workspace

The basic idea is to select a block and drag it into place, also known as drag and drop.

If you just click on it then it'll be placed randomly on the workspace as a disabled Block (a semi-transparent silhouetted version of the block). This&nbsp;means it's not a complete block yet and simply dragging it into place (with the jigsaw peg nested into the root block's jigsaw hole) will lock it into being a normal Block.

You'll still possibly have other attached pieces of the block that are also **shadow blocks**. For example, the feed names and operators, until you select appropriate values or replace the shadow blocks with other blocks. If a shadow block is showing an acceptable value, then you may leave it and continue as long as the block is attached to the root (directly or indirectly).

![](https://cdn-learn.adafruit.com/assets/assets/000/128/162/medium800thumb/community_support_2024-02-2121-21-59-ezgif.com-video-to-gif-converter.jpg?1709061717)

### Block Menus
Finally you'll want to know is that there is a context-menu. That is the name for the menu that appears when you right-click with the mouse (or Control key + click on Mac), and the menu varies according to where the mouse is (contextual menu).

Here I've right clicked on a _Reactive action_ block, placed from the Triggers category toolbox. You can see options for collapse blocks, inline inputs, disable and enable blocks, and finally delete them.  
Do try it out as you may find some very helpful.

![community_support_Screenshot_2024-02-21_211151.png](https://cdn-learn.adafruit.com/assets/assets/000/127/902/medium640/community_support_Screenshot_2024-02-21_211151.png?1708550277)

Inline? Yes, the compact form of the block, allowing you to read it in a single line rather than large multi-line blocks.

Here's an example with collapsed (top), and inline versions of both Trigger and Action blocks:

![](https://cdn-learn.adafruit.com/assets/assets/000/127/913/medium800/community_support_Screenshot_2024-02-21_220038.png?1708552881)

## Block Types

Now on to learning the details of the blocks specific to Adafruit IO.

Please note that these may change in the future as we try to break down the complexity into smaller more useful chunks. But, the same functionality will remain so check back here if you need a refresher.

### Triggers Category

The input blocks for our Blockly workspace.

Here you select from: a **reactive** trigger (that trigger based on a new feed value), **scheduled** trigger (based on a simple repeating time schedule), or a&nbsp;_delay_ **timer** trigger (where the trigger fires based on a new feed value, but the trigger is delayed before starting by a chosen delay value)

![](https://cdn-learn.adafruit.com/assets/assets/000/127/918/medium800/community_support_Screenshot_2024-02-21_225230.png?1708565481)

- **Reactive** - This is the base block for a reactive action, it has two comparators, and an operator (the condition), along with a repetition time limit. Notify on reset will email you when the condition is no longer true.  
  
- **Timer** - Identical to reactive for evaluating a condition, except in addition to verifying the condition has been met, it is also delayed before flowing through from the Trigger to the Action.

![community_support_Screenshot_2024-02-21_225230.png](https://cdn-learn.adafruit.com/assets/assets/000/127/916/medium640/community_support_Screenshot_2024-02-21_225230.png?1708565442)

You choose the delay after the condition is met, before the resulting Action is fired, and whether a new value matching the condition should extend the timer.

- **Scheduled** - This makes use of the Schedules category toolbox, and you can select various different timing schemes, like hourly, daily, weekly, annually etc.

![community_support_Screenshot_2024-02-21_225230.png](https://cdn-learn.adafruit.com/assets/assets/000/127/919/medium640/community_support_Screenshot_2024-02-21_225230.png?1708565770)

### Schedules Category

This category has all the different scheduling blocks that can be used to complete the "When" option of the Scheduled Trigger Block.

With options for hourly, daily, weekly, monthly, annually, and possibly more coming soon (sunrise anybody?), there is a lot of possibility in these blocks!

Make sure to use the mouse-over tooltips as there are a few intricacies left over from the old system, allowing more complex triggering that you might first expect.

![community_support_Screenshot_2024-02-21_225257.png](https://cdn-learn.adafruit.com/assets/assets/000/128/195/medium640/community_support_Screenshot_2024-02-21_225257.png?1709124793)

An example is the hourly block, which can trigger more than once per hour, as we used to allow it to be used in a more advanced way a bit like Cron if you've ever heard of that (a Linux job scheduler).

![community_support_Screenshot_2024-02-21_225307.png](https://cdn-learn.adafruit.com/assets/assets/000/128/196/medium640/community_support_Screenshot_2024-02-21_225307.png?1709124829)

### Actions Category

The outputs category for our Blockly workspace, one Action block is required and also only one is allowed, similarly to the Trigger blocks.

This is where you select what happens next. Do you send an email or SMS, publish a new value to another feed, or use a webhook to trigger a process on another server? Let's find out more...

- **Publish to a Feed** - this sends a new value to a feed, currently, this is a fixed value (a number or string) that you define in advance.

If you need more than one output, then consider chaining actions by publishing to an intermediate feed or webserver (using webhooks), then have additional actions triggered by that intermediate feed or webhook.

![community_support_Screenshot_2024-02-23_132932.png](https://cdn-learn.adafruit.com/assets/assets/000/127/941/medium640/community_support_Screenshot_2024-02-23_132932.png?1708695027)

- **Email&nbsp;** - Comes with a suggested template, where you can use the placeholders in double curly braces like `{{value}}`, to insert the value from a feed, along with `feed_name`, `time` and other useful fields.  
  
- **SMS** - Same sort of thing as email, but you must have the number registered for Adafruit IO, which is under [your Adafruit Account -\> Services -\> IO+ SMS settings](https://accounts.adafruit.com/settings/phone). It's currently an [IO+ powerup](https://learn.adafruit.com/welcome-to-adafruit-io/io-plus) (like our [Weather service](https://io.adafruit.com/services)), US/CA numbers only and 25 SMS per day.

![community_support_Screenshot_2024-02-23_133315.png](https://cdn-learn.adafruit.com/assets/assets/000/127/943/medium640/community_support_Screenshot_2024-02-23_133315.png?1708695214)

- **Webhook** - This sends a templated message to a web server. It is used to call out to existing external services, for example, a discord bot, automation services, or some other JSON-loving device. (Does not need to be JSON, you control the message that is sent).  
There is also the option to use Form Encoding instead.

![community_support_Screenshot_2024-02-21_225351.png](https://cdn-learn.adafruit.com/assets/assets/000/127/923/medium640/community_support_Screenshot_2024-02-21_225351.png?1708566809)

### Values Category

The blocks in the Values category are used as comparators (things to compare against), and for template related blocks (like email/SMS/webhooks) to allow the placeholders to be correctly populated. This means it's technically possible to publish the value of a different feed in an email to the feed that was triggering our action.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/940/medium800/community_support_Screenshot_2024-02-23_131956.png?1708694430)

First is the most frequently used block, the Feed block, and then different value types required in some conditional / logic operations. If you don't know the term, a boolean is only ever either true or false.

Most things on Adafruit IO accept strings or numbers interchangeably, effectively everything is treated as a string when being evaluated, but that cannot and should not be relied upon. For one thing, machines do care about the difference, so it's best to stick to one data type and use the specific one you need for the output.

### Operators

Operators aren't a toolbox category, but they're just as important as the other blocks!

An operator is used to specify the type of comparison, or check, that is done against the comparators (things being checked).

![](https://cdn-learn.adafruit.com/assets/assets/000/127/925/medium800/community_support_Screenshot_2024-02-21_234458.png?1708564209)

These are the conditional operators, the noble&nbsp; **equals** , the infinitely useful&nbsp; **any** , and many more:

1. **any** - when _any_ value arrives, it is said to match and the conditional check is true.
2. **greater than**
3. **greater than or equal to**
4. **less than**
5. **less than or equal to**
6. **equals**
7. **not equal to**
8. **includes&nbsp;** - search within an incoming feed/value for another feed/value.

## String it all together: A Quick Demo:
Here's a simple run-through of recreating my burnt toast reactive action, and on the next page(s) you'll go through some other more useful "real" examples to help you learn how to use each trigger type.

![](https://cdn-learn.adafruit.com/assets/assets/000/127/914/medium800thumb/community_support_2024-02-2122-27-51-ezgif.com-video-to-gif-converter.jpg?1708555131)

# How to use Blockly for Actions on Adafruit IO

## Example Actions

# Example 1: Notify me if the air quality in my house is bad

A very common use of actions is to have it send you an email or SMS if a feed value hits a certain threshold. In this case, I have an Adafruit PMSA003I Air Quality breakout board that is reading the air quality in my kitchen. I want to get notified by email if the air quality gets unhealthy in my home while cooking. Here is a simple Blockly action to make that work:

![](https://cdn-learn.adafruit.com/assets/assets/000/127/951/medium800/community_support_AQI_example.png?1708713030)

As you can see above, I chose the Reactive trigger as I only want to get notified if something happens (not regularly). I chose my AQI feed, and have it emailing me if the value ever gets higher than 50. I don't want to get a ton of messages about this, so I have it limit how often I get the emails to a max of every 15 minutes. I then checked Notify on Reset as this will let me know when the feed has gone back below 50.

For the Action, I have it sending me an email. You can change the information in the subject and body of the email or leave it as the default. Also notice you can use the `{{feed_name}}` and `{{value}}` shortcodes in both the subject and the body to personalize the email you get. Then in the 'using:' portion of the email action be sure to put the same feed as above. This is how the email action knows what to use for the shortcodes.

# Example 2: Send me an SMS with the temperature outside every day at 8:00am

In this example I have the action set up to send me the temperature from my outdoor weather station every morning at 8:00am.

![](https://cdn-learn.adafruit.com/assets/assets/000/128/139/medium800/community_support_Screenshot_2024-02-27_103931.png?1709052062)

Warning: 

I used the Scheduled trigger with the Daily Schedule block, and set it to 8:00 AM. You can also switch the block to the daily, weekly, monthly, or annually block. Then I used the SMS (IO+ only) block for the action, and set the feed to my temperature feed.

# Example 3: Turn on buzzer if sump pump is too full, and then turn buzzer off again after 1 minute.

This example is a bit more advanced and will require two actions to get it to work right. The first action we want to set up is to turn the buzzer on if the water in the sump pump well reaches a certain level.

![](https://cdn-learn.adafruit.com/assets/assets/000/128/144/medium800/community_support_Screenshot_2024-02-27_110711.png?1709053722)

Here we used the Reactive block to turn on my buzzer by setting the Buzzer feed to TRUE. This will happen if the Reactive feed detects that the water in my sump pump well is more than 80% full. I will check the water level in the sump pump well every 30 minutes.

Then I will create a second action and use the Timer block to trigger at the same time. But the Trigger block works differently in that it won't take action until a set amount of time has passed. In this case we want to turn off that buzzer after 1 minute.

![](https://cdn-learn.adafruit.com/assets/assets/000/128/145/medium800/community_support_Screenshot_2024-02-27_111135.png?1709053968)

The most important things here are that I have it set to Run After 1 min (so the buzzer will run for 1 minute before we turn it off). The next thing is that I have Extend Timer checked. This will make sure that as long as the SumpLevel feed is higher than 80, the buzzer won't turn back on again after it has been turned off.


## Featured Products

### Adafruit IO+ Subscription Pass – One Year

[Adafruit IO+ Subscription Pass – One Year](https://www.adafruit.com/product/3792)
The all-in-one Internet of Things service from Adafruit you know and love is now _even better_ with IO+. The 'plus' stands for MORE STUFF! More feeds, dashboards, storage, speed. Power up your [Adafruit IO](https://io.adafruit.com/) with the $99 pass for 1 year of the...

In Stock
[Buy Now](https://www.adafruit.com/product/3792)
[Related Guides to the Product](https://learn.adafruit.com/products/3792/guides)
### Adafruit IO+ 1 Year Subscription Card

[Adafruit IO+ 1 Year Subscription Card](https://www.adafruit.com/product/3980)
It's the Internet of the Things!&nbsp;[Adafruit IO+](https://io.adafruit.com/plus) is the easiest way to stream, log, and interact with your data. Whether you're interesting in&nbsp;datalogging or communicating with your microcontroller over the web, Adafruit IO is our cloud...

In Stock
[Buy Now](https://www.adafruit.com/product/3980)
[Related Guides to the Product](https://learn.adafruit.com/products/3980/guides)

## Related Guides

- [Monitor Your Greenhouse with a No-Code Environmental Sensor](https://learn.adafruit.com/monitor-your-greenhouse-with-a-no-code-environmental-sensor.md)
- [Adafruit IO Basics: Analog Input](https://learn.adafruit.com/adafruit-io-basics-analog-input.md)
- [CircuitPython Webcam with OV2640](https://learn.adafruit.com/circuitpython-webcam-with-ov2640.md)
- [Where's My Friend? A Location-Aware Display with PyPortal and ItsASnap](https://learn.adafruit.com/where-s-my-friend-a-location-display-frame-with-pyportal.md)
- [Scan QR Codes with CircuitPython](https://learn.adafruit.com/scan-qr-codes-with-circuitpython.md)
- [Use Apple HomeKit Devices with itsaSNAP and Adafruit IO](https://learn.adafruit.com/use-apple-homekit-devices-with-itsasnap.md)
- [All the Internet of Things - Episode Four: Adafruit IO](https://learn.adafruit.com/all-the-internet-of-things-episode-four-adafruit-io.md)
- [Adafruit IO Basics: Color](https://learn.adafruit.com/adafruit-io-basics-color.md)
- [How to Add a New Board to WipperSnapper](https://learn.adafruit.com/how-to-add-a-new-board-to-wippersnapper.md)
- [Integrating Color Sensors with itsaSNAP and HomeKit](https://learn.adafruit.com/integrating-color-sensors-with-itsasnap-and-homekit.md)
- [DIY IoT Doorbell Camera with MEMENTO](https://learn.adafruit.com/diy-iot-doorbell-camera-with-memento.md)
- [Using ItsaSNAP for HomeKit PIR Motion Detection](https://learn.adafruit.com/itsasnap-homekit-pir-motion-detection.md)
- [CircuitPython OctoPrint Controller and Monitor](https://learn.adafruit.com/circuitpython-octoprint-controller-and-monitor.md)
- [Pico W PiCowBell Case](https://learn.adafruit.com/pico-w-picowbell-case.md)
- [Adafruit IO Basics: Analog Output](https://learn.adafruit.com/adafruit-io-basics-analog-output.md)
