# IoT Power Outlet with CircuitPython and Adafruit IO

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/094/894/medium800/sensors_6690DC6F-CEA5-4771-8156-C10B3D4226DC_1_105_c.jpeg?1600702623)

 **Do you want to control your lights or appliances using a microcontroller?&nbsp;** Build an internet-connected electrical outlet with an Adafruit PyPortal and CircuitPython. The guide uses a controllable four outlet power relay to avoid hazardous high voltages. Connect the project to [Adafruit IO](http://io.adafruit.com/), our free Internet-of-Things platform, to **control your appliances from anywhere in the world**.

&nbsp;

## Adafruit IO Dashboard

**Adafruit IO is the easiest way to stream, log, and interact with your data.** &nbsp;It's built from the ground up to be easy to use - we do the hard stuff so you can focus on the fun stuff.

You'll build a customizable dashboard to turn your A/C appliance on or off and can optionally add extra blocks to read feedback from the appliance

![sensors_Kapture_2020-09-21_at_11.50.59.gif](https://cdn-learn.adafruit.com/assets/assets/000/094/896/medium640thumb/sensors_Kapture_2020-09-21_at_11.50.59.jpg?1600703492)

## Parts

You will need the following parts to complete this guide:

### Adafruit PyPortal - CircuitPython Powered Internet Display

[Adafruit PyPortal - CircuitPython Powered Internet Display](https://www.adafruit.com/product/4116)
 **PyPortal** , our easy-to-use IoT device that allows you to create all the things for the “Internet of Things” in minutes. Make custom touch screen interface GUIs, all open-source, and Python-powered using&nbsp;tinyJSON / APIs to get news, stock, weather, cat photos,...

In Stock
[Buy Now](https://www.adafruit.com/product/4116)
[Related Guides to the Product](https://learn.adafruit.com/products/4116/guides)
![Front view of a Adafruit PyPortal - CircuitPython Powered Internet Display with a pyportal logo image on the display. ](https://cdn-shop.adafruit.com/640x480/4116-00.jpeg)

### Controllable Four Outlet Power Relay Module version 2

[Controllable Four Outlet Power Relay Module version 2](https://www.adafruit.com/product/2935)
Say goodbye to hazardous high voltage wiring and create the [Internet of Things](https://www.adafruit.com/categories/342) with safe, reliable power control. The **IoT Power Relay** &nbsp;from&nbsp;[Digital...](http://www.digital-loggers.com/iot.html)

In Stock
[Buy Now](https://www.adafruit.com/product/2935)
[Related Guides to the Product](https://learn.adafruit.com/products/2935/guides)
![Controllable Four Outlet Power Relay Module](https://cdn-shop.adafruit.com/640x480/2935-13.jpg)

### STEMMA JST PH 2mm 3-Pin to Male Header Cable - 200mm

[STEMMA JST PH 2mm 3-Pin to Male Header Cable - 200mm](https://www.adafruit.com/product/3893)
This cable will let you turn a JST PH 3-pin cable port into 3 individual wires with high-quality 0.1" male header plugs on the end. We're carrying these to match up with our Hallowing, for extending and connecting sensors or LEDs - and the wires are even color coded!

<a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/3893)
[Related Guides to the Product](https://learn.adafruit.com/products/3893/guides)
![Angled shot of STEMMA JST PH 3-Pin to Male Header Cable - 200mm.](https://cdn-shop.adafruit.com/640x480/3893-03.jpg)

### 5V 2.5A Switching Power Supply with 20AWG MicroUSB Cable

[5V 2.5A Switching Power Supply with 20AWG MicroUSB Cable](https://www.adafruit.com/product/1995)
Our all-in-one 5V 2.5 Amp + MicroUSB cable power adapter is the perfect choice for powering single-board computers like Raspberry Pi, BeagleBone, or anything else that's power-hungry!

This adapter was specifically designed to provide 5.25V, not 5V, but we still call it a 5V USB...

In Stock
[Buy Now](https://www.adafruit.com/product/1995)
[Related Guides to the Product](https://learn.adafruit.com/products/1995/guides)
![MicroUSB power supply with bundled cable and U.S. plugs.](https://cdn-shop.adafruit.com/640x480/1995-02.jpg)

# IoT Power Outlet with CircuitPython and Adafruit IO

## Adafruit IO Setup

If you do not already have an Adafruit IO account set up, head over to&nbsp;[io.adafruit.com](http://io.adafruit.com/)&nbsp;to link your Adafruit.com account to Adafruit IO.

## Obtain Adafruit IO Key

You will to need to obtain your Adafruit IO username and secret API key.

**[Navigate to your profile](http://io.adafruit.com/profile)&nbsp;and click the View AIO Key button**&nbsp;to retrieve them. Write them down in a safe place, you'll need them later in this guide.

![](https://cdn-learn.adafruit.com/assets/assets/000/094/781/medium800thumb/sensors_3d_printing_io_key_retrr.jpg?1600353927)

## Create Feed

The first step is to create a new Adafruit IO feed to hold the state of the relay. Navigate to the&nbsp;[feeds page](https://io.adafruit.com/feeds)&nbsp;on Adafruit IO. Then click&nbsp; **Actions&nbsp;-\> Create New Feed** , and **name this feed** &nbsp; **relay**.&nbsp;

- If you do not already know how to create a feed, head over to&nbsp;[Adafruit IO Basics: Feeds](https://learn.adafruit.com/adafruit-io-basics-feeds).

![](https://cdn-learn.adafruit.com/assets/assets/000/094/773/medium800/sensors_IO_-_Feeds.png?1600352688)

## Create Dashboard

Next, you'll create a dashboard to write to the relay feed. Navigate to [the dashboards page on Adafruit IO](https://io.adafruit.com/dashboards). Then click&nbsp; **Actions -\> Create New Dashboard** , and **name this dashboard**  **the name of the appliance you want to control**. I'm controlling an Air Conditioner in my office, so I named the dashboard _Air Conditioner_.&nbsp;

- If you do not know how to create or use Dashboards in Adafruit IO, head over to the&nbsp;[Adafruit IO Basics: Dashboards](https://learn.adafruit.com/adafruit-io-basics-dashboards)&nbsp;guide.

![](https://cdn-learn.adafruit.com/assets/assets/000/094/774/medium800/sensors_IO_-_Dashboards.png?1600352746)

## Add Toggle Block to Dashboard

Next, add a Toggle Block to your dashboard. Click the '+' button next to the dashboard title.

![](https://cdn-learn.adafruit.com/assets/assets/000/094/776/medium800/sensors_IO_-_Air_Conditioner.png?1600353296)

From the block selection modal, **select the Toggle Button**.

On Choose Feed, **select the relay feed**.

On Block Settings, **change the Block Title to Power**.

**Click Create Block**

![sensors_IO_-_Air_Conditioner.png](https://cdn-learn.adafruit.com/assets/assets/000/094/777/medium640/sensors_IO_-_Air_Conditioner.png?1600353402)

![sensors_IO_-_Air_Conditioner.png](https://cdn-learn.adafruit.com/assets/assets/000/094/778/medium640/sensors_IO_-_Air_Conditioner.png?1600353518)

![sensors_IO_-_Air_Conditioner.png](https://cdn-learn.adafruit.com/assets/assets/000/094/779/medium640/sensors_IO_-_Air_Conditioner.png?1600353572)

Your completed dashboard should look like the following:

![](https://cdn-learn.adafruit.com/assets/assets/000/094/780/medium800/sensors_IO_-_Air_Conditioner.png?1600353690)

# IoT Power Outlet with CircuitPython and Adafruit IO

## CircuitPython Setup

## Install CircuitPython

Some CircuitPython compatible boards come with CircuitPython installed. Others are&nbsp;_CircuitPython-ready_, but need to have it installed. As well, you may want to update the version of CircuitPython already installed on your board. The steps are the same for installing and updating.&nbsp;

- To&nbsp;**install (or update) your CircuitPython board**,&nbsp;[follow this page and come back here when you've successfully installed (or updated) CircuitPython.](https://learn.adafruit.com/welcome-to-circuitpython/installing-circuitpython)

## CircuitPython Library Installation

First make sure you are running the&nbsp;[latest version of Adafruit CircuitPython](https://github.com/adafruit/circuitpython/releases)&nbsp;for your board.

Next you'll need to install the necessary libraries&nbsp;to use the hardware--carefully follow the steps to find and install these libraries from&nbsp;[Adafruit's CircuitPython library bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle)&nbsp;matching your version of CircuitPython.&nbsp;

CircuitPython hardware shows up on your computer operating system as a flash drive when connected via usb. The flash drive is called&nbsp; **CIRCUITPY** &nbsp;and contains a number of files. You will need to add additional files to enable the features of this project.

First, create a folder on the drive named lib if it is not already there.

Ensure your board's&nbsp; **lib** &nbsp;folder has the following files and folders **&nbsp;** copied over. The version of the files must be the same major version as your version of CircuitPython (i.e. 4.x for 4.x, 5.x for 5.x, etc.)

- **adafruit\_bus\_device**
- **adafruit\_minimqtt**
- **adafruit\_logging.mpy**
- **adafruit\_esp32spi**
- **adafruit\_requests.mpy**
- **adafruit\_io**
- **neopixel.mpy**

# IoT Power Outlet with CircuitPython and Adafruit IO

## Create Your settings.toml File

CircuitPython works with WiFi-capable boards to enable you to make projects that have network connectivity. This means working with various passwords and API keys. As of [CircuitPython 8](https://circuitpython.org/downloads), there is support for a **settings.toml** file. This is a file that is stored on your **CIRCUITPY** drive, that contains all of your secret network information, such as your SSID, SSID password and any API keys for IoT services. It is designed to separate your sensitive information from your **code.py** file so you are able to share your code without sharing your credentials.

CircuitPython previously used a **secrets.py** file for this purpose. The **settings.toml** file is quite similar.

Warning: Your **settings.toml** file should be stored in the main directory of your **CIRCUITPY** drive. It should not be in a folder.

## CircuitPython **settings.toml** File

This section will provide a couple of examples of what your **settings.toml** file should look like, specifically for CircuitPython WiFi projects in general.

The most minimal **settings.toml** file must contain your WiFi SSID and password, as that is the minimum required to connect to WiFi. Copy this example, paste it into your **settings.toml** , and update:

- `your_wifi_ssid`
- `your_wifi_password`

```auto
CIRCUITPY_WIFI_SSID = "your_wifi_ssid"
CIRCUITPY_WIFI_PASSWORD = "your_wifi_password"
```

Many CircuitPython network-connected projects on the Adafruit Learn System involve using Adafruit IO. For these projects, you must _also_ include your Adafruit IO username and key. Copy the following example, paste it into your settings.toml file, and update:

- `your_wifi_ssid`
- `your_wifi_password`
- `your_aio_username`
- `your_aio_key`

```auto
CIRCUITPY_WIFI_SSID = "your_wifi_ssid"
CIRCUITPY_WIFI_PASSWORD = "your_wifi_password"
ADAFRUIT_AIO_USERNAME = "your_aio_username"
ADAFRUIT_AIO_KEY = "your_aio_key"
```

Some projects use different variable names for the entries in the **settings.toml** file. For example, a project might use `ADAFRUIT_AIO_ID` in the place of `ADAFRUIT_AIO_USERNAME`. **If you run into connectivity issues, one of the first things to check is that the names in the settings.toml file match the names in the code.**

Warning: Not every project uses the same variable name for each entry in the **settings.toml** file! Always verify it matches the code.

## **settings.toml** File Tips
Here is an example **settings.toml** file.

```auto
# Comments are supported
CIRCUITPY_WIFI_SSID = "guest wifi"
CIRCUITPY_WIFI_PASSWORD = "guessable"
CIRCUITPY_WEB_API_PORT = 80
CIRCUITPY_WEB_API_PASSWORD = "passw0rd"
test_variable = "this is a test"
thumbs_up = "\U0001f44d"
```

In a **settings.toml** file, it's important to keep these factors in mind:

- Strings are wrapped in double quotes; ex: `"your-string-here"`
- Integers are _ **not** _ quoted and may be written in decimal with optional sign (`+1`, `-1`, `1000`) or hexadecimal (`0xabcd`).
  - Floats (decimal numbers), octal (`0o567`) and binary (`0b11011`) are not supported.

- Use `\u` escapes for weird characters, `\x` and `\ooo` escapes are not available in **.toml** files
  - Example: `\U0001f44d` for 👍 (thumbs up emoji) and `\u20ac` for € (EUR sign)

- Unicode emoji, and non-ASCII characters, stand for themselves as long as you're careful to save in "UTF-8 without BOM" format

&nbsp;

&nbsp;

When your&nbsp; **settings.toml&nbsp;** file is ready, you can save it in your text editor with the **.toml** &nbsp;extension.

![adafruit_products_dotToml.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/071/medium640/adafruit_products_dotToml.jpg?1671034293)

## Accessing Your **settings.toml** Information in **code.py**
In your **code.py** file, you'll need to `import` the `os` library to access the **settings.toml** file. Your settings are accessed with the `os.getenv()` function. You'll pass your settings entry to the function to import it into the **code.py** file.

```python
import os

print(os.getenv("test_variable"))
```

![](https://cdn-learn.adafruit.com/assets/assets/000/117/072/medium800/adafruit_products_tomlOutput.jpg?1671034496)

In the upcoming CircuitPython WiFi examples, you'll see how the **settings.toml&nbsp;** file is used for connecting to your SSID and accessing your API keys.

# IoT Power Outlet with CircuitPython and Adafruit IO

## Internet Connect!

# Connect to WiFi

OK, now that you have your&nbsp; **settings.toml** file set up - you can connect to the Internet.

To do this, you need to first install a few libraries, into the lib folder on your **CIRCUITPY** drive. Then you need to update **code.py** with the example script.

Thankfully, we can do this in one go. In the example below, click the **Download Project Bundle** button below to download the necessary libraries and the **code.py** file in a zip file. Extract the contents of the zip file, open the directory **examples/** and then click on the directory that matches the version of CircuitPython you're using and copy the contents of that directory to your **CIRCUITPY** drive.

Your **CIRCUITPY** drive should now look similar to the following image:

![CIRCUITPY](https://adafruit.github.io/Adafruit_CircuitPython_Bundle/esp32spi_esp32spi_simpletest.py.png )

Info: Update to CircuitPython 9.2.x or later to use this example.

https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI/blob/main/examples/esp32spi_simpletest.py

And save it to your board, with the name **code.py**.

Don't forget you'll also need to create the **settings.toml** file as seen above, with your WiFi ssid and password.

In a serial console, you should see something like the following. For more information about connecting with a serial console, view the guide [Connecting to the Serial Console](https://learn.adafruit.com/welcome-to-circuitpython/kattni-connecting-to-the-serial-console).

```terminal
&gt;&gt;&gt; import wifitest
ESP32 SPI webclient test
ESP32 found and in idle mode
Firmware vers. 1.7.5
MAC addr: 24:C9:DC:BD:0F:3F
	HomeNetwork             RSSI: -46
	HomeNetwork             RSSI: -76
	Fios-12345              RSSI: -92
	FiOS-AB123              RSSI: -92
	NETGEAR53               RSSI: -93
Connecting to AP...
Connected to HomeNetwork 	RSSI: -45
My IP address is 192.168.1.245
IP lookup adafruit.com: 104.20.39.240
Ping google.com: 30 ms
Fetching text from http://wifitest.adafruit.com/testwifi/index.html
----------------------------------------
This is a test of Adafruit WiFi!
If you can read this, its working :)
----------------------------------------

Fetching json from http://wifitest.adafruit.com/testwifi/sample.json
----------------------------------------
{'fun': True, 'company': 'Adafruit', 'founded': 2005, 'primes': [2, 3, 5], 'pi': 3.14, 'mixed': [False, None, 3, True, 2.7, 'cheese']}
----------------------------------------
Done!
```

Going over the example above, here's a breakdown of what the program is doing:

- Initialize the ESP32 over SPI using the SPI port and 3 control pins:

```python
esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)

#...

else:
    spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
```

- Get the socket pool and the SSL context, and then tell the `adafruit_requests` library about them.

```python
pool = adafruit_connection_manager.get_radio_socketpool(esp)
ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp)
requests = adafruit_requests.Session(pool, ssl_context)
```

- Verify an ESP32 is found, checks the firmware and MAC address

```auto
if esp.status == adafruit_esp32spi.WL_IDLE_STATUS:
    print("ESP32 found and in idle mode")
print("Firmware vers.", esp.firmware_version)
print("MAC addr:", ":".join("%02X" % byte for byte in esp.MAC_address))
```

- Perform a scan of all access points it can see and print out the name and signal strength.

```python
for ap in esp.scan_networks():
    print("\t%-23s RSSI: %d" % (ap.ssid, ap.rssi))
```

- Connect to the AP we've defined here, then print out the local IP address. Then attempt to do a domain name lookup and ping google.com to check network connectivity. (Note sometimes the ping fails or takes a while; this isn't a big deal.)

```python
print("Connecting to AP...")
while not esp.is_connected:
    try:
        esp.connect_AP(ssid, password)
    except OSError as e:
        print("could not connect to AP, retrying: ", e)
        continue
print("Connected to", esp.ap_info.ssid, "\tRSSI:", esp.ap_info.rssi)
print("My IP address is", esp.ipv4_address)
print(
    "IP lookup adafruit.com: %s" % esp.pretty_ip(esp.get_host_by_name("adafruit.com"))
)
```

Now we're getting to the really interesting part of the example program. We've written a library for web fetching web data, named [adafruit\_requests](https://github.com/adafruit/Adafruit_CircuitPython_Requests). It is a lot like the regular Python library named [requests](https://requests.readthedocs.io/en/latest/). This library allows you to send HTTP and HTTPS requests easily and provides helpful methods for parsing the response from the server.

- Here is the part of the example program is fetching text data from a URL.

```python
TEXT_URL = "http://wifitest.adafruit.com/testwifi/index.html"  # Further up in the program

# ...

print("Fetching text from", TEXT_URL)
r = requests.get(TEXT_URL)
print('-' * 40)
print(r.text)
print('-' * 40)
r.close()
```

- Finally, here the program is fetching some JSON data. The `adafruit_requests` library will parse the JSON into a Python dictionary whose structure is the same as the structure of the JSON.

```auto
JSON_URL = "http://wifitest.adafruit.com/testwifi/sample.json"   # Further up in the program

# ...

print("Fetching json from", JSON_URL)
r = requests.get(JSON_URL)
print('-' * 40)
print(r.json())
print('-' * 40)
r.close()
```

# Advanced Requests Usage

Want to send custom HTTP headers, parse the response as raw bytes, or handle a response's http status code in your CircuitPython code?

We've written an&nbsp;example to show advanced usage of the requests module below.

To use with CircuitPython, you need to first install a few libraries, into the lib folder on your **CIRCUITPY** drive. Then you need to update **code.py** with the example script.

Thankfully, we can do this in one go. In the example below, click the **Download Project Bundle** button below to download the necessary libraries and the **code.py** file in a zip file. Extract the contents of the zip file, open the directory **examples/** and then click on the directory that matches the version of CircuitPython you're using and copy the contents of that directory to your **CIRCUITPY** drive.

https://github.com/adafruit/Adafruit_CircuitPython_Requests/blob/main/examples/esp32spi/requests_esp32spi_advanced.py

Your **CIRCUITPY** drive should now look similar to the following image:

![CIRCUITPY](https://adafruit.github.io/Adafruit_CircuitPython_Bundle/requests_esp32spi_requests_esp32spi_advanced.py.png )

# WiFi Manager

The way the examples above connect to WiFi works but it's a little finicky. Since WiFi is not necessarily so reliable, you may have disconnects and need to reconnect. For more advanced uses, we recommend using the `WiFiManager` class. It will wrap the connection/status/requests loop for you - reconnecting if WiFi drops, resetting the ESP32 if it gets into a bad state, etc.

Here's a more advanced example that shows using the `WiFiManager` and also how to fetch the current time from a web source.

https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI/blob/main/examples/esp32spi_localtime.py

# Further Information

For more information on the basics of doing networking in CircuitPython, see this guide:

### Networking in CircuitPython

[Networking in CircuitPython](https://learn.adafruit.com/networking-in-circuitpython)
# IoT Power Outlet with CircuitPython and Adafruit IO

## Code PyPortal with CircuitPython

## Add CircuitPython Code

In the embedded code element below, click on the&nbsp; **Download: Project Zip** &nbsp;link, and save the .zip archive file to your computer.

Then,&nbsp; **uncompress the .zip file** , it will unpack to a folder named **Adafruit\_IO\_Power\_Relay**.

Copy the contents of **Adafruit\_IO\_Power\_Relay** &nbsp;directory to your PyPortal's&nbsp; **CIRCUITPY** &nbsp;drive.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/Adafruit_IO_Power_Relay/code.py

Once all the files are copied from your computer to the PyPortal, you should have the following files on your&nbsp; **CIRCUITPY** &nbsp;drive:

![](https://cdn-learn.adafruit.com/assets/assets/000/094/788/medium800/sensors_lib_relay_portal.png?1600376387)

## **settings.toml** File Setup

Add your WiFi credentials and your AdafruitIO credentials to settings.toml. You can find your AIO username key from&nbsp;[io.adafruit.com](https://io.adafruit.com/). Simply click the **&nbsp;** _Adafruit IO Key_&nbsp;on the right hand side of the Adafruit IO header to obtain this information.

```python
CIRCUITPY_WIFI_SSID = "your_wifi_ssid"
CIRCUITPY_WIFI_PASSWORD = "your_wifi_password"
AIO_USERNAME = "your_aio_username"
AIO_KEY = "your_aio_key"
TIMEZONE = "America/New_York" # http://worldtimeapi.org/timezones
```

## Test Code

Before wiring everything up, it's important to test the code so it works as-expected.

Open the CircuitPython REPL. The following should output in the REPL:

```python
code.py output:
Connecting to WiFi...
Connected!
Connecting to Adafruit IO...
Connected to Adafruit IO!
Subscribed to brubell/feeds/relay
```

 **Navigate to the Adafruit IO Dashboard you created earlier and toggle the Power switch.**

The REPL should output _"Turning Relay ON"_

![](https://cdn-learn.adafruit.com/assets/assets/000/094/789/medium800thumb/sensors_toggle_test_on.jpg?1600377339)

Toggling the power switch to the off position should output _"Turning Relay OFF"&nbsp;_in the REPL.

![](https://cdn-learn.adafruit.com/assets/assets/000/094/790/medium800thumb/sensors_toggle_test_off.jpg?1600377347)

# IoT Power Outlet with CircuitPython and Adafruit IO

## Assembly and Wiring

Warning: 

The green screw terminal comes firmly inserted into the relay. With your hands or a&nbsp;[spudger](https://www.adafruit.com/product/3434), **pull the screw terminal out of the relay's case**.

This part may require some extra force to pull it out.

![sensors_IMG_3087_2.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/793/medium640/sensors_IMG_3087_2.jpg?1600442724)

![sensors_IMG_3088_2.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/794/medium640/sensors_IMG_3088_2.jpg?1600442802)

Using a flathead screwdriver, **unscrew each of the screw terminals**.

![sensors_ezgif.com-crop_(3).gif](https://cdn-learn.adafruit.com/assets/assets/000/094/797/medium640thumb/sensors_ezgif.com-crop_%283%29.jpg?1600443931)

With the STEMMA male header cable,&nbsp; **push the white cable into the left screw terminal. Screw the terminal screw clock-wise to fasten the cable.**

**Make sure to give it it a&nbsp;_very gentle&nbsp;_tug to make sure it's securely attached!**

Repeat the above steps for the black header cable and the right screw terminal. Ignore the red (power) header cable.

![sensors_screw_terminakl.png](https://cdn-learn.adafruit.com/assets/assets/000/094/812/medium640/sensors_screw_terminakl.png?1600448141)

Push the screw terminal back into the relay.

![](https://cdn-learn.adafruit.com/assets/assets/000/094/829/medium800/sensors_IMG_3174_2.jpg?1600454361)

 **Plug the&nbsp;**** JST PH 3-pin header into **the PyPortal's** D3 port**.&nbsp;

![sensors_IMG_3127.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/799/medium640/sensors_IMG_3127.jpg?1600443509)

![sensors_IMG_3134.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/800/medium640/sensors_IMG_3134.jpg?1600443533)

The PyPortal needs constant power to receive commands from Adafruit IO. The relay has an _always ON_ port which does not get toggled by the PyPortal.

Plug a power adapter (at least 5V 2A) into the relay's _always ON_ port.

![](https://cdn-learn.adafruit.com/assets/assets/000/094/945/medium800/sensors_DC05D61F-59B8-4102-BC2B-01AAE501F216_1_105_c.jpeg?1600724786)

Connect the PyPortal to the power adapter's MicroUSB cable.

![sensors_IMG_3197.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/802/medium640/sensors_IMG_3197.jpg?1600443689)

![sensors_IMG_3224.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/803/medium640/sensors_IMG_3224.jpg?1600443782)

Connect the power adapter of the appliance to one of the two _normally OFF_ ports on the relay.

![](https://cdn-learn.adafruit.com/assets/assets/000/094/810/medium800/sensors_IMG_3263_2.jpg?1600447680)

# IoT Power Outlet with CircuitPython and Adafruit IO

## Code Usage

Turn the relay's power switch on by toggling the red switch on top of the relay.

![](https://cdn-learn.adafruit.com/assets/assets/000/094/891/medium800/sensors_20032A8A-26FB-41D4-98E9-40E7BED0C939_1_105_c.jpeg?1600702198)

The PyPortal should boot up. The code connects the PyPortal to your WiFi network. Then, it connects to Adafruit IO and subscribes to the feed you set up earlier.

![](https://cdn-learn.adafruit.com/assets/assets/000/094/889/medium800thumb/sensors_ezgif.com-gif-maker_%282%29.jpg?1600701529)

On a web browser, navigate to the Adafruit IO Dashboard you created earlier.&nbsp;

Tap (or click) the _Power_ switch to turn your appliance on.

![](https://cdn-learn.adafruit.com/assets/assets/000/094/893/medium800thumb/sensors_turn_on_ac.jpg?1600702484)

Toggle the power switch again to turn your appliance off.

![](https://cdn-learn.adafruit.com/assets/assets/000/094/946/medium800thumb/sensors_turnoff_ac.jpg?1600727404)

 **That's it! You have successfully connected an appliance to the internet using Adafruit IO.**

# IoT Power Outlet with CircuitPython and Adafruit IO

## Code Walkthrough

Set up the PyPortal's **D3** pin as a DigitalInOut object and set the direction to output.&nbsp;

```python
# Set up a pin for controlling the relay
power_pin = DigitalInOut(board.D3)
power_pin.switch_to_output()
```

Now, set up the _relay_ feed as a string variable named `feed_relay`

```python
### Feeds ###
# Set up a feed named Relay for subscribing to the relay feed on Adafruit IO
feed_relay = os.getenv("AIO_USERNAME") + "/feeds/relay"
```

The following code snippet consists of MQTT callback methods. For an explanation of how these methods function, [please see this section of the MQTT in CircuitPython guide](https://learn.adafruit.com/mqtt-in-circuitpython/code-walkthrough#minimqtt-callback-methods-3034067-9).

```python
### Code ###

# Define callback methods which are called when events occur
# pylint: disable=unused-argument, redefined-outer-name
def connected(client, userdata, flags, rc):
    # This function will be called when the client is connected
    # successfully to the broker.
    print("Connected to Adafruit IO!")

def disconnected(client, userdata, rc):
    # This method is called when the client is disconnected
    print("Disconnected from Adafruit IO!")

def subscribe(client, userdata, topic, granted_qos):
    # This method is called when the client subscribes to a new feed.
    print("Subscribed to {0}".format(topic))

def unsubscribe(client, userdata, topic, pid):
    # This method is called when the client unsubscribes from a feed.
    print("Unsubscribed from {0} with PID {1}".format(topic, pid))

def on_message(client, topic, message):
    # Method callled when a client's subscribed feed has a new value.
    print("New message on topic {0}: {1}".format(topic, message))
```

When the Adafruit IO feed _Your-AIO-Username/feeds/relay_ receives new data, the following method executes and evaluates the value on the feed.

If the value is "ON", the relay is turned on by setting the pin high. If the value is "OFF", the relay is turned off by setting the pin low.&nbsp;

```python
def on_relay_msg(client, topic, value):
    # Called when relay feed obtains a new value
    print("Turning Relay %s"%value)
    if value == "ON":
        power_pin.value = True
    elif value == "OFF":
        power_pin.value = False
    else:
        print("Unexpected value received on relay feed.")
```

Next, connect to the WiFi network and set up a MQTT client to connect to Adafruit IO's MQTT broker with your credentials.

```python
pool = adafruit_connection_manager.get_radio_socketpool(esp)
ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp)

# Set up a MiniMQTT Client
client = MQTT.MQTT(
    broker="io.adafruit.com",
    username=os.getenv("AIO_USERNAME"),
    password=os.getenv("AIO_KEY"),
    socket_pool=pool,
    ssl_context=ssl_context,
)
```

Now, set up the callback methods above by connecting them to the client's default callback properties.&nbsp;

```python
# Setup the callback methods above
client.on_connect = connected
client.on_disconnect = disconnected
client.on_subscribe = subscribe
client.on_unsubscribe = unsubscribe
client.on_message = on_message
```

The `on_relay_message` method is not a default MiniMQTT client callback, so it's added as a custom callback, which will execute `on_relay_msg()` when new data is received.

```python
# Add a callback to the relay feed
client.add_topic_callback(feed_relay, on_relay_msg)
```

Connect to the Adafruit IO MQTT broker and subscribe to the relay feed.

```python
# Connect the client to Adafruit IO
print("Connecting to Adafruit IO...")
client.connect()

# Subscribe to all updates on relay feed
client.subscribe(feed_relay)
```

The code within the `while True` loop will check for new messages on the relay feed every 50 milliseconds. If there's an issue with the network connection, the WiFi connection will reset and the MQTT client will reconnect to Adafruit IO.

```python
while True:
    try: # Poll for new messages on feed_relay
        client.loop()
    except (ValueError, RuntimeError) as e:
        print("Failed to get data, retrying\n", e)
        wifi.reset()
        client.reconnect()
        continue
    time.sleep(0.05)
```

# IoT Power Outlet with CircuitPython and Adafruit IO

## Going Further: Add a Feedback Indicator

![](https://cdn-learn.adafruit.com/assets/assets/000/094/944/medium800thumb/sensors_ezgif.com-video-to-gif_%2829%29.jpg?1600724306)

If you experience a power or network outage - your Dashboard's power toggle may not be accurate.

While the PyPortal will re-connect to the network, Adafruit IO toggling the button may not actually be turning the appliance on or off. You will need to add some way of measuring feedback (such as the power status) from the appliance.

A simple way of adding a feedback mechanism is by placing a light sensor over the appliance's power indicator LED to detect if the appliance is actually turned on or off.&nbsp;

**Plug a BH1750, a small inexpensive light sensor, into your PyPortal to measure the light value from the appliance's power indicator LED**. Then, create a new Adafruit IO Feed to hold the light sensor's value.

Add some new code to the PyPortal to measure the light sensor's value at a predefined interval, evaluate if the appliance is turned on or off, and send the status back to Adafruit IO.&nbsp;

To wrap it all up, you'll add an **Indicator Block to your Adafruit IO Dashboard to display the appliance's actual power status**.

## Parts

We'll need two additional parts to complete this section

### Adafruit BH1750 Light Sensor - STEMMA QT / Qwiic

[Adafruit BH1750 Light Sensor - STEMMA QT / Qwiic](https://www.adafruit.com/product/4681)
This is the **BH1750 16-bit Ambient Light Sensor** from Rohm. Because of how important it is to humans and most other living things, sensing the amount of light in an environment is a common place to get started when learning to work with microcontrollers and sensors. Should we...

Out of Stock
[Buy Now](https://www.adafruit.com/product/4681)
[Related Guides to the Product](https://learn.adafruit.com/products/4681/guides)
![Angled shot of black, rectangular light sensor breakout board.](https://cdn-shop.adafruit.com/640x480/4681-05.jpg)

You'll also need a JST PH to JST SH cable to connect the BH1750 sensor to the PyPortal's I2C port.

### 4-pin JST PH to JST SH Cable - STEMMA to QT / Qwiic

[4-pin JST PH to JST SH Cable - STEMMA to QT / Qwiic](https://www.adafruit.com/product/4424)
Are you a maker in the midst of&nbsp;a [**STEMMA**](https://learn.adafruit.com/introducing-adafruit-stemma-qt/what-is-stemma) dilemma? This 200mm long 4-wire cable is a fantastic chimera-cable fitted with **STEMMA QT / Sparkfun Qwiic JST SH** on one end,...

In Stock
[Buy Now](https://www.adafruit.com/product/4424)
[Related Guides to the Product](https://learn.adafruit.com/products/4424/guides)
![Angled shot of 4-pin JST PH to JST SH Cable. ](https://cdn-shop.adafruit.com/640x480/4424-02.jpg)

## Add Feed

You will need a feed to hold the sensor's value. Navigate to your Adafruit IO Feeds page and **click Actions -\> Create New Feed**. Name the feed status and **click create**.

![](https://cdn-learn.adafruit.com/assets/assets/000/094/897/medium800/sensors_IO_-_Feeds.png?1600703688)

## Add Block to Dashboard

Navigate to the dashboard you created earlier. **Click Create New Block** (+ icon).

Select the indicator block

Select the feed you just created, _status_

**Click Create Block**

![sensors_IO_-_Air_Conditioner.png](https://cdn-learn.adafruit.com/assets/assets/000/094/898/medium640/sensors_IO_-_Air_Conditioner.png?1600703905)

![sensors_IO_-_Air_Conditioner.png](https://cdn-learn.adafruit.com/assets/assets/000/094/899/medium640/sensors_IO_-_Air_Conditioner.png?1600703945)

![sensors_IO_-_Air_Conditioner.png](https://cdn-learn.adafruit.com/assets/assets/000/094/900/medium640/sensors_IO_-_Air_Conditioner.png?1600704054)

Your dashboard should look like the screenshot below:

![](https://cdn-learn.adafruit.com/assets/assets/000/094/901/medium800/sensors_IO_-_Air_Conditioner.png?1600704150)

## Wiring
Plug the BH1750 Light Sensor into the Stemma JST PH connector.&nbsp;

Then, plug the JST SH connector into the I2C port on your PyPortal.

![sensors_4A6289F7-95C6-4F2E-B7AC-2002CE99745D_1_105_c.jpeg](https://cdn-learn.adafruit.com/assets/assets/000/094/904/medium640/sensors_4A6289F7-95C6-4F2E-B7AC-2002CE99745D_1_105_c.jpeg?1600706341)

![sensors_5872BDA1-3EC6-4E75-9EB2-B2B1247E734E_1_105_c.jpeg](https://cdn-learn.adafruit.com/assets/assets/000/094/905/medium640/sensors_5872BDA1-3EC6-4E75-9EB2-B2B1247E734E_1_105_c.jpeg?1600706358)

![sensors_4CECF27B-031B-46D6-9DF6-BEA61146FA06_1_105_c.jpeg](https://cdn-learn.adafruit.com/assets/assets/000/094/906/medium640/sensors_4CECF27B-031B-46D6-9DF6-BEA61146FA06_1_105_c.jpeg?1600706374)

Locate the Power LED on your appliance and&nbsp; **attach the light sensor above the power LED** &nbsp;using tape.

We suggest using black tape, such as gaffer's tape to avoid light leakage.

![sensors_B126E0C8-79EC-4414-8E50-BE47AEF001F0_1_105_c.jpeg](https://cdn-learn.adafruit.com/assets/assets/000/094/920/medium640/sensors_B126E0C8-79EC-4414-8E50-BE47AEF001F0_1_105_c.jpeg?1600716628)

## **CircuitPython Installation of BH1750 Library**

You'll need to install the&nbsp;[Adafruit CircuitPython BH1750](https://github.com/adafruit/Adafruit_CircuitPython_BH1750)&nbsp;library on your CircuitPython board.

First make sure you are running the&nbsp;[latest version of Adafruit CircuitPython](https://learn.adafruit.com/welcome-to-circuitpython/installing-circuitpython)&nbsp;for your board.

Next you'll need to install the necessary libraries&nbsp;to use the hardware--carefully follow the steps to find and install these libraries from&nbsp;[Adafruit's CircuitPython library bundle](https://circuitpython.org/libraries).&nbsp; Our CircuitPython starter guide has&nbsp;[a great page on how to install the library bundle](https://learn.adafruit.com/welcome-to-circuitpython/circuitpython-libraries).

Before continuing make sure your board's&nbsp; **lib** &nbsp;folder or root filesystem has the&nbsp; **adafruit\_bh1750.mpy&nbsp;** file **&nbsp;and adafruit\_bus\_device&nbsp;** folder **&nbsp;** copied over.

## CircuitPython Code

Copy code\_light\_sensor.py to your PyPortal's&nbsp; **CIRCUITPY** &nbsp;drive and **rename the file to code.py.**

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/Adafruit_IO_Power_Relay/code_light_sensor/code.py

## Code Usage

Connect up your PyPortal's STEMMA cables and turn on the relay outlet. Once the PyPortal is connected to the internet, navigate to the Adafruit IO Dashboard and tap the toggle switch block to turn the appliance on.

The appliance should turn on and the indicator block should light up green, indicating it is turned on.

![](https://cdn-learn.adafruit.com/assets/assets/000/094/941/medium800thumb/sensors_ezgif.com-video-to-gif_%2829%29.jpg?1600723938)

Toggling the switch to the off position should turn the appliance off and the indicator block should turn red.

## Light Sensor Calibration

We wrote this guide for a LG Air Conditioner. Other appliances use different LEDs which provide different illuminance measurements. If the status indicator block is not responding, you may need to calibrate the light sensor for your appliance.

In the embedded code element below, click on the&nbsp; **Download: Project Zip** &nbsp;link, and save the .zip archive file to your computer.

Then,&nbsp; **uncompress the .zip file** , it will unpack to a folder named **bh1750\_simpletest**.

Copy **bh1750\_simpletest.py&nbsp;** to your PyPortal's&nbsp; **CIRCUITPY** &nbsp;drive and **rename the file to code.py.**

https://github.com/adafruit/Adafruit_CircuitPython_BH1750/blob/main/examples/bh1750_simpletest.py

Connect your PyPortal to power. With the light sensor placed over the light source, turn the PyPortal on. Turn the appliance on. The display will show&nbsp;the ambient light level in lux, the&nbsp;[SI derived unit](https://en.wikipedia.org/wiki/SI_derived_unit)&nbsp;for&nbsp;[measuring illuminance](https://en.wikipedia.org/wiki/Lux).

Write this value down. You may wish to average some of the readings together.

![sensors_A8126BCC-1352-4D08-A669-5BD82EC3D60E_1_105_c.jpeg](https://cdn-learn.adafruit.com/assets/assets/000/094/936/medium640/sensors_A8126BCC-1352-4D08-A669-5BD82EC3D60E_1_105_c.jpeg?1600721641)

In the **code\_light\_sensor.py** , modify the line `APPLIANCE_ON_LUX = 30.0` to the light value you recorded.


## Featured Products

### Adafruit PyPortal - CircuitPython Powered Internet Display

[Adafruit PyPortal - CircuitPython Powered Internet Display](https://www.adafruit.com/product/4116)
 **PyPortal** , our easy-to-use IoT device that allows you to create all the things for the “Internet of Things” in minutes. Make custom touch screen interface GUIs, all open-source, and Python-powered using&nbsp;tinyJSON / APIs to get news, stock, weather, cat photos,...

In Stock
[Buy Now](https://www.adafruit.com/product/4116)
[Related Guides to the Product](https://learn.adafruit.com/products/4116/guides)
### Controllable Four Outlet Power Relay Module version 2

[Controllable Four Outlet Power Relay Module version 2](https://www.adafruit.com/product/2935)
Say goodbye to hazardous high voltage wiring and create the [Internet of Things](https://www.adafruit.com/categories/342) with safe, reliable power control. The **IoT Power Relay** &nbsp;from&nbsp;[Digital...](http://www.digital-loggers.com/iot.html)

In Stock
[Buy Now](https://www.adafruit.com/product/2935)
[Related Guides to the Product](https://learn.adafruit.com/products/2935/guides)
### 5V 2.5A Switching Power Supply with 20AWG MicroUSB Cable

[5V 2.5A Switching Power Supply with 20AWG MicroUSB Cable](https://www.adafruit.com/product/1995)
Our all-in-one 5V 2.5 Amp + MicroUSB cable power adapter is the perfect choice for powering single-board computers like Raspberry Pi, BeagleBone, or anything else that's power-hungry!

This adapter was specifically designed to provide 5.25V, not 5V, but we still call it a 5V USB...

In Stock
[Buy Now](https://www.adafruit.com/product/1995)
[Related Guides to the Product](https://learn.adafruit.com/products/1995/guides)
### STEMMA JST PH 2mm 3-Pin to Male Header Cable - 200mm

[STEMMA JST PH 2mm 3-Pin to Male Header Cable - 200mm](https://www.adafruit.com/product/3893)
This cable will let you turn a JST PH 3-pin cable port into 3 individual wires with high-quality 0.1" male header plugs on the end. We're carrying these to match up with our Hallowing, for extending and connecting sensors or LEDs - and the wires are even color coded!

<a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/3893)
[Related Guides to the Product](https://learn.adafruit.com/products/3893/guides)
### Adafruit BH1750 Light Sensor - STEMMA QT / Qwiic

[Adafruit BH1750 Light Sensor - STEMMA QT / Qwiic](https://www.adafruit.com/product/4681)
This is the **BH1750 16-bit Ambient Light Sensor** from Rohm. Because of how important it is to humans and most other living things, sensing the amount of light in an environment is a common place to get started when learning to work with microcontrollers and sensors. Should we...

Out of Stock
[Buy Now](https://www.adafruit.com/product/4681)
[Related Guides to the Product](https://learn.adafruit.com/products/4681/guides)
### 4-pin JST PH to JST SH Cable - STEMMA to QT / Qwiic

[4-pin JST PH to JST SH Cable - STEMMA to QT / Qwiic](https://www.adafruit.com/product/4424)
Are you a maker in the midst of&nbsp;a [**STEMMA**](https://learn.adafruit.com/introducing-adafruit-stemma-qt/what-is-stemma) dilemma? This 200mm long 4-wire cable is a fantastic chimera-cable fitted with **STEMMA QT / Sparkfun Qwiic JST SH** on one end,...

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

## Related Guides

- [Adafruit PyPortal - IoT for CircuitPython](https://learn.adafruit.com/adafruit-pyportal.md)
- [Adafruit BH1750 Ambient Light Sensor](https://learn.adafruit.com/adafruit-bh1750-ambient-light-sensor.md)
- [Infinite Text Adventure](https://learn.adafruit.com/infinite-text-adventure.md)
- [Adafruit IO Basics: AirLift](https://learn.adafruit.com/adafruit-io-basics-airlift.md)
- [PyPortal Email Display with Zapier and Adafruit IO](https://learn.adafruit.com/pyportal-email-display.md)
- [PyPortal Smart Thermometer with Analog Devices ADT7410, Adafruit IO and CircuitPython](https://learn.adafruit.com/pyportal-smart-thermometer-with-analog-devices-adt7410-adafruit-io-and-circuitpython.md)
- [CircuitPython Day 2020 Countdown Clock](https://learn.adafruit.com/circuitpython-day-2020-countdown-clock.md)
- [AdaBox 011](https://learn.adafruit.com/adabox011.md)
- [PyPortal Twitter Follows Trophy](https://learn.adafruit.com/pyportal-twitter-follows-trophy.md)
- [Adafruit IO Basics: Schedule Actions](https://learn.adafruit.com/adafruit-io-basics-scheduled-triggers.md)
- [PyPortal GitHub Stars Trophy](https://learn.adafruit.com/pyportal-github-stars-trophy.md)
- [CircuitPython Turtle Graphics](https://learn.adafruit.com/circuitpython-turtle-graphics.md)
- [Smart Mirror with PyPortal](https://learn.adafruit.com/smart-mirror-with-pyportal.md)
- [Data Logging IoT Weight Scale](https://learn.adafruit.com/data-logging-iot-weight-scale.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)
- [CircuitPython Your Own Adventure](https://learn.adafruit.com/circuit-python-your-own-adventure.md)
