# LLM Agent Embodiment Kit

## Overview

![Feather S3 reverse TFT on a perma proto breadboard with a PDM mic, piezo buzzer, and NeoPixel stick. A STEMMA QT cable connects the feather to a BME280, VEML770, DRV2605, and LIS3DH. A cute happy face is displayed on the Feather's TFT](https://cdn-learn.adafruit.com/assets/assets/000/144/252/medium800/sensors_full_build.png?1779386051 )

Yellow: Inspired by Olivia Zhu's *A Minimal Self-Perceiving Embodiment for Large Language Models* (2026, [zenodo](https://doi.org/10.5281/zenodo.19903098)). The accompanying code is on [GitHub](https://github.com/oliviazzzu/minimal-embodiment).

The core idea of this project is to give an LLM agent access to a device that can be used to sense the environment that its human user is in, and to express itself in that environment using sensor feedback loops to confirm the physical effects. This version of the project uses an&nbsp;[Adafruit ESP32-S3 Reverse TFT Feather](https://www.adafruit.com/product/5691) as the central hardware.

This quote from the Abstract section of the inspiration paper sums it up nicely.

&gt; We present a minimal hardware-software architecture that grants a large language model a closed-loop physical embodiment: six input modalities (temperature, humidity, atmospheric pressure, illuminance, motion, sound) across four sensor modules, three output channels (haptic, visual, audio), and two input-output couplings that let the LLM verify its outputs land in the physical world. The system runs on a single microcontroller exposed as a network-accessible API; a remote LLM client perceives its surroundings, expresses into them, and receives back — via paired on-board sensors — confirmation of its own outputs in two modalities (audio via microphone, haptic via accelerometer), constituting self-perception loops. We identify this three-part structure — perception, expression, and self-perception of expression — as a minimal sufficient configuration for closed-loop physical agency — the capacity to act in a physical environment and perceive the consequence — in an LLM.

Info: The feedback loop is what makes this 'embodied' compared to just a bot with sensors because it will be 'grounded' in the reality of being able to actuate-then-sense and thus have verifiable behaviors instead of just an 'agent with sensors' that can drift from reality

With the embodiment kit an agent can sense:

- temperature,&nbsp;humidity, and pressure with a [BME280](https://www.adafruit.com/product/2652)
- sound level with a [PDM mic](https://www.adafruit.com/product/3492)
- light with a [VEML770](https://www.adafruit.com/product/4162)
- motion with an [LIS3DH](https://www.adafruit.com/product/2809)
- button presses with 3 built-in buttons

It can output effects with the following:

- sound with a [piezo buzzer](https://www.adafruit.com/product/160)
- RGB light with [NeoPixels](https://www.adafruit.com/product/1426)
- haptic vibration with a [DRV2605](https://www.adafruit.com/product/2305) + haptic motor
- TFT display to show faces or text

The buzzer, NeoPixels, and haptic motor are all tied to sensor feedback loops to enable confirmation of their effect. Buzzer with PDM mic, NeoPixels with light sensor, and haptic motor with accelerometer.

### Adaptability

The hardware and software is built to be modular and adaptable to different needs and use-cases. The embodiment kit was primarily intended for use with an LLM agent, but its CLI script can easily be used from a terminal or integrated in other non-LLM contexts as well. This guide documents building the kit with all of the hardware components listed above, but the code is easy to adapt to different or fewer sensors.

## New Territory

This project differs from the original version by Olivia Zhu in a number of ways. It's implemented in CircuitPython instead of Arduino. Communication between embodiment device and agent occurs over Adafruit IO MQTT, or on the local network with a small HTTP server running on the microcontroller itself. A larger bridge server is not necessary. A NeoPixel stick has been added and paired with the lux sensor for an additional feedback loop.

The TFT display is a bit larger and can handle color. A set of cute facial expression sprites are used instead of programmatic drawing. The display can be used to show text in addition to graphics. The push buttons built-in to the Feather can be used to prompt the user with up to 3 options and receive feedback about their selection. Different specific sensors and breakouts are used, but they can sense the same things. STEMMA QT cables are used for all I2C connections.

## Parts
### Adafruit ESP32-S3 Reverse TFT Feather

[Adafruit ESP32-S3 Reverse TFT Feather](https://www.adafruit.com/product/5691)
Like Missy Elliot, we like to ["put our [Feather] down, flip it and reverse it"](https://www.youtube.com/watch?v=cjIvu7e6Wq8)&nbsp;and that's exactly what we've done with this new development board. It's basically our **<a...></a...>**

Out of Stock
[Buy Now](https://www.adafruit.com/product/5691)
[Related Guides to the Product](https://learn.adafruit.com/products/5691/guides)
![Video of a rectangular microcontroller with a TFT display. A pink manicured finger presses each of the tactile buttons, which are recognized on the TFT display.](https://cdn-shop.adafruit.com/product-videos/640x480/5691-05.jpg)

### Adafruit Perma-Proto Half-sized Breadboard PCB - Single

[Adafruit Perma-Proto Half-sized Breadboard PCB - Single](https://www.adafruit.com/product/1609)
Customers have asked us to carry basic perf-board, but we never liked the look of most basic perf: it's always crummy quality, with pads that flake off and no labeling. Then we thought about how people **actually** prototype - usually starting with a solderless breadboard and...

In Stock
[Buy Now](https://www.adafruit.com/product/1609)
[Related Guides to the Product](https://learn.adafruit.com/products/1609/guides)
![Top view of Adafruit Perma-Proto Half-sized Breadboard PCB.](https://cdn-shop.adafruit.com/640x480/1609-00.jpg)

### Adafruit PDM MEMS Microphone Breakout

[Adafruit PDM MEMS Microphone Breakout](https://www.adafruit.com/product/3492)
An exotic new microphone has arrived in the Adafruit shop, a **PDM MEMS Microphone**! PDM is the 'third' kind of microphone you can integrate with electronics, apart from analog or I2S. These microphones are very commonly used in products, but are rarely seen in maker...

In Stock
[Buy Now](https://www.adafruit.com/product/3492)
[Related Guides to the Product](https://learn.adafruit.com/products/3492/guides)
![Angled shot of blue, square-shaped MEMS microphone breakout.](https://cdn-shop.adafruit.com/640x480/3492-07.jpg)

### Piezo Buzzer

[Piezo Buzzer](https://www.adafruit.com/product/160)
Piezo buzzers are used for making beeps, tones and alerts. This one is petite but loud! Drive it with 3-30V peak-to-peak square wave. To use, connect one pin to ground (either one) and the other pin to a square wave out from a timer or microcontroller. For the loudest tones, stay around 4 KHz,...

In Stock
[Buy Now](https://www.adafruit.com/product/160)
[Related Guides to the Product](https://learn.adafruit.com/products/160/guides)
![Bread-board friendly Piezo Buzzer](https://cdn-shop.adafruit.com/640x480/160-01.jpg)

### NeoPixel Stick - 8 x 5050 RGB LED with Integrated Drivers

[NeoPixel Stick - 8 x 5050 RGB LED with Integrated Drivers](https://www.adafruit.com/product/1426)
Make your own little LED strip arrangement with this stick of NeoPixel LEDs. We crammed 8 of the tiny 5050 (5mm x 5mm) smart RGB LEDs onto a PCB with mounting holes and a chainable design. Use only one microcontroller pin to control as many as you can chain together! Each LED is addressable as...

In Stock
[Buy Now](https://www.adafruit.com/product/1426)
[Related Guides to the Product](https://learn.adafruit.com/products/1426/guides)
![NeoPixel Stick with 8 x 5050 RGB LED ](https://cdn-shop.adafruit.com/640x480/1426-05.jpg)

### Adafruit BME280 I2C or SPI Temperature Humidity Pressure Sensor

[Adafruit BME280 I2C or SPI Temperature Humidity Pressure Sensor](https://www.adafruit.com/product/2652)
Bosch has stepped up their game with their new BME280 sensor, an environmental sensor with temperature, barometric pressure&nbsp;and&nbsp;humidity! This sensor is great for all sorts of indoor environmental sensing and can even be used in both I2C and SPI!

This precision sensor from...

In Stock
[Buy Now](https://www.adafruit.com/product/2652)
[Related Guides to the Product](https://learn.adafruit.com/products/2652/guides)
![small, rectangle-shaped, BME280 temperature humidity pressure sensor breakout board.](https://cdn-shop.adafruit.com/640x480/2652-04.jpg)

### Adafruit VEML7700 Lux Sensor - I2C Light Sensor

[Adafruit VEML7700 Lux Sensor - I2C Light Sensor](https://www.adafruit.com/product/4162)
Vishay has a lot of light sensors out there, and this is a nice simple lux sensor that's easy to add to any microcontroller. Most light sensors just give you a number for brighter/darker ambient lighting. The VEML7700 makes your life easier by calculating the lux, which is an SI unit for...

In Stock
[Buy Now](https://www.adafruit.com/product/4162)
[Related Guides to the Product](https://learn.adafruit.com/products/4162/guides)
![Angled shot of lux sensor breakout.](https://cdn-shop.adafruit.com/640x480/4162-10.jpg)

### Adafruit DRV2605L Haptic Motor Controller - STEMMA QT / Qwiic

[Adafruit DRV2605L Haptic Motor Controller - STEMMA QT / Qwiic](https://www.adafruit.com/product/2305)
The DRV2605 from TI is a fancy little motor driver. Rather than controlling a stepper motor or DC motor, its designed specifically for controlling **haptic** motors - buzzers and vibration motors. Normally one would just turn those kinds of motors on and off, but this driver has...

In Stock
[Buy Now](https://www.adafruit.com/product/2305)
[Related Guides to the Product](https://learn.adafruit.com/products/2305/guides)
![Video of a haptic controller breakout board with a vibrating motor disc soldered to it. The disc vibrates against the surface.](https://cdn-shop.adafruit.com/product-videos/640x480/2305-05.jpg)

### Adafruit LIS3DH Triple-Axis Accelerometer (+-2g/4g/8g/16g)

[Adafruit LIS3DH Triple-Axis Accelerometer (+-2g/4g/8g/16g)](https://www.adafruit.com/product/2809)
The **LIS3DH** &nbsp;is a very popular low power **triple-axis accelerometer**. It's low-cost, but has just about every 'extra' you'd want in an accelerometer:

- Three axis sensing, 10-bit...

Out of Stock
[Buy Now](https://www.adafruit.com/product/2809)
[Related Guides to the Product](https://learn.adafruit.com/products/2809/guides)
![Top down view of a Adafruit LIS3DH Triple-Axis Accelerometer.](https://cdn-shop.adafruit.com/640x480/2809-08.jpg)

### 36-pin 0.1" Female header - pack of 5!

[36-pin 0.1" Female header - pack of 5!](https://www.adafruit.com/product/598)
Female header is like the duct tape of electronics. Its great for connecting things together, soldering to perf-boards, sockets for wires or break-away header, etc. We go through these guys real fast, and thought that given how handy they are, we'd offer them in a pack of five!  
<br...></br...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/598)
[Related Guides to the Product](https://learn.adafruit.com/products/598/guides)
![pack of five, 36-pin 0.1 inch Female header](https://cdn-shop.adafruit.com/640x480/598-04.jpg)

### Male Header 36-pin 0.1" Short Break-away Type - Pack of 10

[Male Header 36-pin 0.1" Short Break-away Type - Pack of 10](https://www.adafruit.com/product/3009)
In this world nothing can be said to be certain, except we need headers, headers, and more headers!

**Each pack contains ten 36-pin short break-away male headers, 0.1" pitch. These headers are very short for [matching with our...](https://www.adafruit.com/products/3008)**

Out of Stock
[Buy Now](https://www.adafruit.com/product/3009)
[Related Guides to the Product](https://learn.adafruit.com/products/3009/guides)
![Pack of 10 of 36-pin 0.1 inch Short Break-away Male Header](https://cdn-shop.adafruit.com/640x480/3009-00.jpg)

### STEMMA QT / Qwiic JST SH 4-pin Cable - 100mm Long

[STEMMA QT / Qwiic JST SH 4-pin Cable - 100mm Long](https://www.adafruit.com/product/4210)
This 4-wire cable is a little over 100mm / 4" long and fitted with JST-SH female 4-pin connectors on both ends. Compared with the chunkier JST-PH these are 1mm pitch instead of 2mm, but still have a nice latching feel, while being easy to insert and remove.

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

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

### STEMMA QT / Qwiic JST SH 4-Pin Cable - 50mm Long

[STEMMA QT / Qwiic JST SH 4-Pin Cable - 50mm Long](https://www.adafruit.com/product/4399)
This 4-wire cable is&nbsp;50mm / 1.9" long and fitted with JST SH female 4-pin connectors on both ends. Compared with the chunkier JST PH these are 1mm pitch instead of 2mm, but still have a nice latching feel, while being easy to insert and remove.

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

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

# LLM Agent Embodiment Kit

## Demos

The embodiment kit is a general and open-ended project. By itself, it's just an interface that provides access to the included hardware in a way that is easy to integrate with LLMs agents. It is up to you to decide how the capabilities can best fit into your workflow. This page presents a few example ideas and demonstrations.

https://www.youtube.com/watch?v=J_sr2Z8jFfs

Here are some more ideas for prompts that incorporate the embodiment hardware in various was.

### Unit Test Status
&gt; Please run the unit tests and when finished, beep the buzzer and set the NeoPixels to green or red based on the tests pass or fail status.

### Window Reminder Script
&gt; Please write a script to check the room temperature every 5 minutes. When it goes above 75F use the 
haptic motor, NeoPixels, and display to get my attention and remind me to close the window.

### Research Conclusion Indicator
&gt; Research online whether X hardware can be used with Y software. Once you have a conclusion show a happy face for 'yes they can', a sad face for 'no they cant', or a confused face if it's inconclusive.

### Built Indicator / Test Prompt
&gt; After a successful project build, vibrate the haptic motor and prompt me using the embodiment buttons whether I want to run all tests or only priority tests. Then run the the specified set of tests, defaulting to only priority tests if the prompt times out.

### Rain Warning Script
&gt; Please write a script that checks the local whether and turn on the NeoPixels to light blue if the chance of rain for the day is greater than 60%. Set up a cron task to run the script every day at 7:30 am.

# LLM Agent Embodiment Kit

## Individual Components

![Project components: BME280, VEML770, DRV2605, LIS3DH, piezo buzzer, PDM mic, and NeoPixel stick layed out on a flat surface](https://cdn-learn.adafruit.com/assets/assets/000/144/255/medium800/sensors_individual_components.png?1779387367 )

![Embodiment kit Fritzing diagrams showing the individual components wired with the Feather to a breadboard.](https://cdn-learn.adafruit.com/assets/assets/000/144/411/medium800/sensors_embodiment_kit_assembly_steps_bb.png?1779887269 )

[component_wiring.fzz](https://cdn-learn.adafruit.com/assets/assets/000/144/412/original/component_wiring.fzz?1779887393)
The following pages are embedded sections from the guides for each of the individual components used by the embodiment kit. It's not strictly necessary to follow them for making the embodiment kit, but it makes it easier to understand how each component works in isolation.

The simple test scripts for the piezo buzzer, PDM microphone, and NeoPixels are especially helpful to verify the wiring is working as expected during assembly of the perma-proto breadboard.

Read over them to learn about how to use each component with CircuitPython or if you need to troubleshoot a specific component that isn't working as expected. The pages will depict different microcontrollers that aren't the Feather Reverse TFT used by the kit. Everything works the same, but some may require minor adjustments to code and wiring for pins available on the Feather.

This Fritzing file shows the wiring required for each of the components connected to the proto board and the STEMMA QT chain of breakouts.

# LLM Agent Embodiment Kit

## Piezo Buzzer

To control the piezo from CircuitPython we'll use its built in PWM, or pulse-width modulation, signal generation capabilities.&nbsp; Be sure to read the [CircuitPython analog I/O guide](../../../../circuitpython-basics-analog-inputs-and-outputs/analog-signals) for more details on PWM signals!

Before continuing make sure your hardware is wired up as shown on the previous page.

Next make sure you are running the&nbsp;[latest version of Adafruit CircuitPython](../../../../welcome-to-circuitpython/installing-circuitpython)&nbsp;for your board, then&nbsp;[connect to the board's serial REPL&nbsp;](../../../../welcome-to-circuitpython/the-repl)so you are at the CircuitPython&nbsp; **\>\>\>** &nbsp;prompt.

# Setup

First you need to import a few modules to access the PWM output capabilities of CircuitPython:

```auto
import board
import pwmio
```

Now you can create a PWM signal output that will drive the buzzer to make sound:

```auto
buzzer = pwmio.PWMOut(board.D5, variable_frequency=True)
```

There are a couple important things happening with the line above.&nbsp; This is an initializer which is creating an instance of the PWMOut class and part of that initialization process is specifying these two values:

- **The pin that will be the PWM output.** &nbsp; In this case it's pin D5 on the development board.&nbsp; If you're using a different output be sure to specify the right pin name here (and make sure the pin supports PWM output as mentioned on the previous page!).
- **The variable\_frequency boolean is True.** &nbsp; This is an optional value that we're specifying as a keyword argument to tell the PWM output that we want to be able to change its frequency, or how often the signal changes. &nbsp;By default PWM outputs in CircuitPython have a fixed frequency, but if this special keyword is specified you can instead change the frequency of the output.

# Making Tones with PWM

Now we can generate tones using the PWM output. &nbsp;Remember from the [CircuitPython analog I/O guide PWM page](../../../../circuitpython-basics-analog-inputs-and-outputs/pulse-width-modulation-outputs) a PWM signal is just a fast on/off signal, i.e. a square wave. &nbsp;When a square wave modulates the movement of something, like a buzzer, it generates a pressure wave that the human ear interprets as sound. &nbsp;By changing the frequency, or how often the square wave changes from high to low, you can change the frequency of the tone that you'll hear.

Changing the frequency of the PWM output is easy, just modify the frequency attribute to set a new value in hertz. &nbsp;For example a 440 hz wave is the same pitch as an A4 note in music:

```auto
buzzer.frequency = 440
```

You might notice after setting the frequency above nothing actually happened--no sound is being made by the buzzer. &nbsp;Is the buzzer broken? &nbsp;Nope! &nbsp;There's one more thing you need to do to create the square wave signal, you need to set the duty cycle of the PWM output.

Like the [CircuitPython analog I/O PWM page mentions](../../../../circuitpython-basics-analog-inputs-and-outputs/pulse-width-modulation-outputs) the duty cycle of a signal is the percent of time that it's high vs. low. &nbsp;We want to generate a square wave which is high and low for exactly the same amount of time (i.e. 50% duty cycle). &nbsp;This will generate a square wave of the previously specified frequency on the PWM output, and as a result induce a pressure wave from the buzzer that you'll hear as sound.

To simplify turning on and off the buzzer let's make a couple variables to represent the 0% and 50% duty cycle values that turn the buzzer off and on respectively:

```auto
OFF = 0
ON = 2**15
```

The **ON** value is 2^15, or 32768, which is about half of the maximum duty cycle value (65535).

Now set the buzzer duty cycle to **ON** to start playing the tone at the previously set frequency:

```auto
buzzer.duty_cycle = ON
```

You should hear the buzzer start to play a tone at 440 hz!

To stop the tone playback change the duty cycle to **OFF** or 0%:

```auto
buzzer.duty_cycle = OFF
```

Now the buzzer stops making sound!

You can change the frequency at any time too, whether the buzzer is playing sound or not. &nbsp;Here are some interesting frequency values to try (they're the frequencies for musical notes):

- 262 hz, C4
- 294 hz, D4
- 330 hz, E4
- 349 hz, F4
- 392 hz, G4
- 440 hz, A4
- 494 hz B4

Try turning the buzzer on and changing the frequency between a few note values:

```auto
buzzer.duty_cycle = ON
buzzer.frequency = 262 # C4
buzzer.frequency = 294 # D4
buzzer.frequency = 330 # E4
buzzer.duty_cycle = OFF
```

That's all there is to simple tone playback with a piezo buzzer and CircuitPython's built-in PWM output!

Here's a complete example that will play a scale of tones up and down repeatedly. &nbsp;Save this as **main.py** on your board and be ready after saving it as the music playback will immediately start:

```auto
import time

import board
import pwmio


# Define a list of tones/music notes to play.
TONE_FREQ = [ 262,  # C4
              294,  # D4
              330,  # E4
              349,  # F4
              392,  # G4
              440,  # A4
              494 ] # B4

# Create piezo buzzer PWM output.
buzzer = pulseio.PWMOut(board.D5, variable_frequency=True)

# Start at the first note and start making sound.
buzzer.frequency = TONE_FREQ[0]
buzzer.duty_cycle = 2**15  # 32768 value is 50% duty cycle, a square wave.

# Main loop will go through each tone in order up and down.
while True:
    # Play tones going from start to end of list.
    for i in range(len(TONE_FREQ)):
        buzzer.frequency = TONE_FREQ[i]
        time.sleep(0.5)  # Half second delay.
    # Then play tones going from end to start of list.
    for i in range(len(TONE_FREQ)-1, -1, -1):
        buzzer.frequency = TONE_FREQ[i]
        time.sleep(0.5)
```

# Making Tones With SimpleIO

Another option to generate a tone is with the [SimpleIO module](https://github.com/adafruit/Adafruit_CircuitPython_SimpleIO) for CircuitPython.&nbsp; This module simplifies tone generation by doing all the PWM duty cycle and frequency logic for you automatically.&nbsp; With a simple tone function call you can play a tone for a period of time--no setup or duty cycle calculation necessary!&nbsp; You might find this approach easier to start with for basic tone playback compared to the PWM approach shown above.

To follow this approach you'll need to install the&nbsp;[Adafruit CircuitPython SimpleIO](https://github.com/adafruit/Adafruit_CircuitPython_SimpleIO)&nbsp;library on your CircuitPython board.&nbsp;&nbsp;

First make sure you are running the&nbsp;[latest version of Adafruit CircuitPython](../../../../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://github.com/adafruit/Adafruit_CircuitPython_Bundle).&nbsp; Our introduction guide has&nbsp;[a great page on how to install the library bundle](../../../../welcome-to-circuitpython/circuitpython-libraries)&nbsp;for both express and non-express boards.

Remember for non-express boards like the, you'll need to manually install the necessary libraries from the bundle:

- **simpleio.mpy**

You can also download the&nbsp; **simpleio.mpy** &nbsp;from&nbsp;[its releases page on Github](https://github.com/adafruit/Adafruit_CircuitPython_SimpleIO/releases).

Before continuing make sure your board's lib folder or root filesystem has the **simpleio.mpy&nbsp;** file copied over.

Next&nbsp;[connect to the board's serial REPL&nbsp;](../../../../welcome-to-circuitpython/the-repl)so you are at the CircuitPython&nbsp; **\>\>\>** &nbsp;prompt.&nbsp; Then import the **board** and **simpleio** modules:

```auto
import board
import simpleio
```

Now you'e ready to use the tone function in SimpleIO to play a tone on a pin connected to a piezo buzzer.&nbsp; Try the following to play a 440 hz tone for 1 second:

```auto
    simpleio.tone(board.D5, 440, duration=1.0)
  
```

You should hear a 440 hz tone, or an A4 note, played for one second.&nbsp; The parameters you pass to the tone function control the frequency and duration of the tone:

- The first parameter is the pin connected to the buzzer or speaker, in this case digital pin 5 as shown in the wiring for this guide.
- The second parameter is the frequency in Hz of the tone to play back. This can be a floating point but note that at higher frequencies (\> 10KHz) the precision may not match perfectly
- The last parameter is a keyword **duration** which specifies how long to play the tone in seconds.&nbsp; By default if you don't provide a value here the tone will be played for one second, however you can specify shorter or longer values.

Another example is playing a 400 hz tone for 3 seconds:

```auto
simpleio.tone(board.D5, 400, duration=3.0)
```

Notice how the frequency and duration parameters changed to specify these different values!

That's all there is to basic tone playback on a piezo with the SimpleIO module!&nbsp; Here's another complete example that plays a scale of notes using SimpleIO's tone function.&nbsp; Again save this as a **main.py** on your board to have it run:

```auto
import board

import simpleio


# Define pin connected to piezo buzzer.
PIEZO_PIN = board.D5

# Define a list of tones/music notes to play.
TONE_FREQ = [ 262,  # C4
              294,  # D4
              330,  # E4
              349,  # F4
              392,  # G4
              440,  # A4
              494 ] # B4


# Main loop will go through each tone in order up and down.
while True:
    # Play tones going from start to end of list.
    for i in range(len(TONE_FREQ)):
        simpleio.tone(PIEZO_PIN, TONE_FREQ[i], duration=0.5)
    # Then play tones going from end to start of list.
    for i in range(len(TONE_FREQ)-1, -1, -1):
        simpleio.tone(PIEZO_PIN, TONE_FREQ[i], duration=0.5)
```

# LLM Agent Embodiment Kit

## PDM Mic

It's easy to use the Adafruit PDM microphone breakout with CircuitPython, using the built-in [`audiobusio` module](https://circuitpython.readthedocs.io/en/latest/shared-bindings/audiobusio/ __init__.html) and [`PDMIn` class](https://circuitpython.readthedocs.io/en/latest/shared-bindings/audiobusio/PDMIn.html). It allows you to record an input audio signal from the microphone using PDM.

This page will walk you through wiring up your PDM mic, and using it to print out sound levels to the serial console and show the values on the plotter in Mu.

Info: Only mono input is currently supported.

# CircuitPython Microcontroller Wiring

The following wiring diagrams show how to connect the PDM mic to a Feather M4 Express. If you're using another board, check out the [Where's my PDMIn? section](https://learn.adafruit.com/adafruit-pdm-microphone-breakout/circuitpython#wheres-my-pdmin-4-11) at the end for valid pin combinations for your board. Some boards, like the SAMD21 and SAMD51 have fixed pins that support PDM. Others like the nRF52840 can use _any_ two pins.

The following is the header version of the PDM microphone breakout wired to a Feather M4 Express:

- **Mic 3V** to **Feather 3V**
- **Mic GND** to **Feather Gnd**
- **Mic CLK** to **Feather TX**
- **Mic DAT** to **Feather D12**

![sensors_PDM_Mic_Feather_M4_bb.png](https://cdn-learn.adafruit.com/assets/assets/000/080/198/medium640/sensors_PDM_Mic_Feather_M4_bb.png?1567106674)

The following is the JST version of the PDM microphone breakout wired to a Feather M4 Express:

- **Mic 3V (red wire)** to **Feather 3V**
- **Mic GND (black wire)** to **Feather Gnd**
- **Mic DAT (blue wire)** to **Feather D12**
- **Mic CLK (yellow wire)** to **Feather TX**

![sensors_PDM_Mic_JST_Feather_M4_bb.png](https://cdn-learn.adafruit.com/assets/assets/000/080/204/medium640/sensors_PDM_Mic_JST_Feather_M4_bb.png?1567111022)

If you're using Circuit Playground Express, there is a built in PDM microphone. There is [a guide page dedicated to using Circuit Playground Express and the built-in microphone](https://learn.adafruit.com/sensor-plotting-with-mu-and-circuitpython/sound). If you're using a CPX, check that out instead!

# CircuitPython Usage

As `PDMIn` is built into CircuitPython, no separate libraries are necessary for this example!

Save the following as code.py on your microcontroller board:

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

First you import `time`, `array`, `math`, `board` and `audiobusio`.

Then you have two helper functions. The first one uses math to return a mean, or average. It is used in the second helper. The second one uses math to return a [normalised RMS average](https://en.wikipedia.org/wiki/Root_mean_square). You use these functions to take multiple sound samples really quickly and average them to get a more accurate reading.

Next you set up the microphone object and your samples variable.

Then you use the mic object to start taking sound samples. You use the normalised RMS to find the average of a given set of samples, and you call that the `magnitude`. Last, you `print` the `magnitude` to the serial console.

Note that the Mu plotter looks for **tuple** values to print. Tuples in Python come in parentheses `()` with comma separators. If you have two values, a tuple would look like `(1.0, 3.14)` Since you have only one value, you need to have it print out like&nbsp;`(1.0,)` note the parentheses _around_ the number, and the _comma_ after the number. Thus the extra parentheses and comma in `print((magnitude,))`.

Once you have everything setup and running, try speaking towards the microphone, and watch the plotter immediately react! Move further away from the microphone to cause smaller changes in the plotter line. Move closer to the board to see bigger spikes!

Note that the way that the code works with averaging a given number of readings over time means that short sounds like claps can sometimes get missed. If you feel like your mic is not responding, try a longer sound like a hum or speaking words.

It's a really easy way to test your microphone and see how it reads sound changes!

![](https://cdn-learn.adafruit.com/assets/assets/000/080/206/medium800/sensors_PDM_Mic_Mu_Plotter.png?1567112054)

# Where's my `PDMIn`?

Save the following as code.py on your board, and connect to the serial console to see a list of all the valid `PDMIn` pin combinations. Note: the code will run immediately and only runs once - if you connect to the serial console and don't see anything, press ctrl+D to reload and run the code again.

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

# LLM Agent Embodiment Kit

## NeoPixels

NeoPixels are a revolutionary and ultra-popular way to add lights and color to your project. These stranded RGB lights have the controller inside the LED, so you just push the RGB data and the LEDs do all the work for you. They're a perfect match for CircuitPython!

You can drive 300 NeoPixel LEDs with brightness control (set `brightness=1.0` in object creation) and 1000 LEDs without. That's because to adjust the brightness we have to dynamically recreate the data-stream each write.

![](https://cdn-learn.adafruit.com/assets/assets/000/052/065/medium800/circuitpython_NeoPixelStripPurple.jpg?1521243999)

## Wiring It Up

You'll need to solder up your NeoPixels first. Verify your connection is on the **DATA INPUT** or **DIN** side. Plugging into the DATA OUT or DOUT side is a common mistake! The connections are labeled and some formats have arrows to indicate the direction the data must flow.

For powering the pixels from the board, the 3.3V regulator output can handle about 500mA peak which is about 50 pixels with 'average' use. If you want really bright lights and a lot of pixels, we recommend powering direct from an external power source.

- On Gemma M0 and Circuit Playground Express this is the **Vout** pad - that pad has direct power from USB or the battery, depending on which is higher voltage.
- On Trinket M0, Feather M0 Express, Feather M4 Express, ItsyBitsy M0 Express and ItsyBitsy M4 Express the **USB** or **BAT** pins will give you direct power from the USB port or battery.
- On Metro M0 Express and Metro M4 Express, use the **5V** pin regardless of whether it's powered via USB or the DC jack.
- On QT Py M0, use the **5V** pin.

If the power to the NeoPixels is greater than 5.5V you may have some difficulty driving some strips, in which case you may need to lower the voltage to 4.5-5V or use a level shifter.

Warning: 

![](https://cdn-learn.adafruit.com/assets/assets/000/052/463/medium800/circuitpython_CircuitPythonNeoPIxelGemma_bb.jpg?1522029450)

Info: 

## The Code

This example includes multiple visual effects.

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 **CircuitPython\_Essentials/CircuitPython\_NeoPixel/** 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_Learning_System_Guides/CircuitPython_Essentials_CircuitPython_NeoPixel.png )

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

## Create the LED

The first thing we'll do is create the LED object. The NeoPixel object has two required arguments and two optional arguments. You are required to set the pin you're using to drive your NeoPixels and provide the number of pixels you intend to use. You can optionally set `brightness` and `auto_write`.

**NeoPixels can be driven by any pin.** We've chosen **A1**. To set the pin, assign the variable `pixel_pin` to the pin you'd like to use, in our case `board.A1`.

To provide the number of pixels, assign the variable `num_pixels` to the number of pixels you'd like to use. In this example, we're using a strip of `8`.

We've chosen to set `brightness=0.3`, or 30%.

By default, `auto_write=True`, meaning any changes you make to your pixels will be sent automatically. Since `True` is the default, if you use that setting, you don't need to include it in your LED object at all. We've chosen to set&nbsp;`auto_write=False`. If you set `auto_write=False`, you must include `pixels.show()` each time you'd like to send data to your pixels. This makes your code more complicated, but it can make your LED animations faster!

## NeoPixel Helpers

Next we've included a few helper functions to create the super fun visual effects found in this code. First is `wheel()` which we just learned with the [Internal RGB LED](../../../../circuitpython-essentials/circuitpython-internal-rgb-led). Then we have `color_chase()` which requires you to provide a `color` and the amount of time in seconds you'd like between each step of the chase. Next we have `rainbow_cycle()`, which requires you to provide the mount of time in seconds you'd like the animation to take. Last, we've included a list of variables for our colors. This makes it much easier if to reuse the colors anywhere in the code, as well as add more colors for use in multiple places. Assigning and using RGB colors is explained in [this section of the CircuitPython Internal RGB LED page](../../../../circuitpython-essentials/circuitpython-internal-rgb-led#main-loop).

## Main Loop

Thanks to our helpers, our main loop is quite simple. We include the code to set every NeoPixel we're using to red, green and blue for 1 second each. Then we call `color_chase()`, one time for each `color` on our list with `0.1` second delay between setting each subsequent LED the same color during the chase. Last we call `rainbow_cycle(0)`, which means the animation is as fast as it can be. Increase both of those numbers to slow down each animation!

Note that the longer your strip of LEDs, the longer it will take for the animations to complete.

Info: 

## NeoPixel RGBW

NeoPixels are available in RGB, meaning there are three LEDs inside, red, green and blue. They're also available in RGBW, which includes four LEDs, red, green, blue and white. The code for RGBW NeoPixels is a little bit different than RGB.

_If you run RGB code on RGBW NeoPixels, approximately 3/4 of the LEDs will light up and the LEDs will be the incorrect color even though they may appear to be changing._ This is because NeoPixels require a piece of information for each available color (red, green, blue and possibly white).

Therefore, RGB LEDs require three pieces of information and RGBW LEDs require FOUR pieces of information to work. So when you create the LED object for RGBW LEDs, you'll include `pixel_order=(1, 0, 2, 3)`, which sets the pixel order and indicates four pieces of information involved.

Then, you must include an extra number in every color tuple you create. For example, red will be `(255, 0, 0, 0)`. This is how you send the fourth piece of information. Check out the example below to see how our NeoPixel code looks for using with RGBW LEDs!

## The Code

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 **CircuitPython\_Essentials/CircuitPython\_NeoPixel\_RGBW/** 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_Learning_System_Guides/CircuitPython_Essentials_CircuitPython_NeoPixel_RGBW.png )

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

## Read the Docs

For a more in depth look at what `neopixel` can do, check out [NeoPixel on Read the Docs](https://circuitpython.readthedocs.io/projects/neopixel/en/latest/).

# LLM Agent Embodiment Kit

## BME280

It's easy to use the BME280 sensor with Python or CircuitPython and the [Adafruit CircuitPython BME280](https://github.com/adafruit/Adafruit_CircuitPython_BME280) module.&nbsp; This module allows you to easily write Python code that reads the humidity, temperature, pressure, and more from the sensor.

You can use this sensor with any CircuitPython microcontroller board or with a computer that has GPIO and Python [thanks to Adafruit\_Blinka, our CircuitPython-for-Python compatibility library](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux).

# CircuitPython Microcontroller Wiring

First wire up a BME280 to your board exactly as shown on the previous pages for Arduino.&nbsp; You can use either I2C or SPI wiring, although it's recommended to use I2C for simplicity.&nbsp; Here's an example of wiring a Feather M0 to the sensor with I2C:

- **Board 3V** to **sensor VIN**
- **Board GND** to **sensor GND**
- **Board SCL** to **sensor SCK**
- **Board SDA** to **sensor SDI**

![adafruit_products_BME280_Feather_I2C_STEMMA_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/097/123/medium640/adafruit_products_BME280_Feather_I2C_STEMMA_bb.jpg?1605727115)

![adafruit_products_BME280_Feather_I2C_breadboard_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/097/124/medium640/adafruit_products_BME280_Feather_I2C_breadboard_bb.jpg?1605727139)

![adafruit_products_BME280_Feather_I2C_original.png](https://cdn-learn.adafruit.com/assets/assets/000/097/125/medium640/adafruit_products_BME280_Feather_I2C_original.png?1605727156)

And an example of a Feather M0 wired with hardware SPI:

- **Board 3V** &nbsp;to&nbsp; **sensor VIN**
- **Board GND** &nbsp;to&nbsp; **sensor GND**
- **Board SCK** &nbsp;to&nbsp; **sensor SCK**
- **Board&nbsp;MOSI&nbsp;** to **sensor SDI**
- **Board MISO** to **sensor SDO**
- **Board D5** to **sensor CS** (or use any other free digital I/O pin)

![adafruit_products_BME280_Feather_SPI_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/097/126/medium640/adafruit_products_BME280_Feather_SPI_bb.jpg?1605727186)

![adafruit_products_BME280_Feather_SPI_original.png](https://cdn-learn.adafruit.com/assets/assets/000/097/127/medium640/adafruit_products_BME280_Feather_SPI_original.png?1605727206)

# Python Computer Wiring

Since there's _dozens_ of Linux computers/boards you can use we will show wiring for Raspberry Pi. For other platforms, [please visit the guide for CircuitPython on Linux to see whether your platform is supported](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux).&nbsp;

Here's the Raspberry Pi wired with I2C:

- **Pi 3V3** to **sensor VIN**
- **Pi GND** to **sensor GND**
- **Pi SCL** to **sensor SCK**
- **Pi SDA** to **sensor SDI**

![adafruit_products_BME280_RasPi_I2C_STEMMA_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/097/128/medium640/adafruit_products_BME280_RasPi_I2C_STEMMA_bb.jpg?1605727237)

![adafruit_products_BME280_RasPi_I2C_breadboard_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/097/129/medium640/adafruit_products_BME280_RasPi_I2C_breadboard_bb.jpg?1605727266)

![adafruit_products_BME280_RasPi_I2C_original.png](https://cdn-learn.adafruit.com/assets/assets/000/097/130/medium640/adafruit_products_BME280_RasPi_I2C_original.png?1605727284)

And an example on the Raspberry Pi 3 Model B wired with SPI:

- **Pi 3V3** to&nbsp; **sensor VIN**
- **Pi GND** &nbsp;to&nbsp; **sensor GND**
- **Pi MOSI&nbsp;** to **sensor SDI**
- **Pi MISO** to **sensor SDO**
- **Pi SCLK** &nbsp;to&nbsp; **sensor SCK**
- **Pi #5** to **sensor CS** (or use any other free GPIO pin)

![adafruit_products_BME280_RasPi_SPI_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/097/131/medium640/adafruit_products_BME280_RasPi_SPI_bb.jpg?1605727322)

![adafruit_products_BME280_RasPi_SPI_original.png](https://cdn-learn.adafruit.com/assets/assets/000/097/132/medium640/adafruit_products_BME280_RasPi_SPI_original.png?1605727339)

# CircuitPython Installation of BME280 Library

You'll need to install the&nbsp;[Adafruit CircuitPython BME280](https://github.com/adafruit/Adafruit_CircuitPython_BME280)&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://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases).&nbsp; Our CircuitPython starter guide has [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 lib folder or root filesystem has the&nbsp; **adafruit\_bme280,** and **adafruit\_bus\_device** folders **&nbsp;** copied over. Both of these are folders with library files in them. Make sure to copy the whole folder for both into your **lib** folder!

Next[&nbsp;connect to the board's serial REPL](https://learn.adafruit.com/welcome-to-circuitpython/the-repl) so you are at the CircuitPython&nbsp; **\>\>\>** &nbsp;prompt.

# Python Installation of BME280 Library

You'll need to install the Adafruit\_Blinka library that provides the CircuitPython support in Python. This may also require enabling I2C on your platform and verifying you are running Python 3. [Since each platform is a little different, and Linux changes often, please visit the CircuitPython on Linux guide to get your computer ready](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux)!

Once that's done, from your command line run the following command:

- `sudo pip3 install adafruit-circuitpython-bme280`

If your default Python is version 3 you may need to run 'pip' instead. Just make sure you aren't trying to use CircuitPython on Python 2.x, it isn't supported!

# CircuitPython & Python Usage

To demonstrate the usage of the sensor we'll initialize it and read the temperature, humidity, and more from the board's Python REPL.

If you're using an I2C connection run the following code to import the necessary modules and initialize the I2C connection with the sensor:

```python
import board
from adafruit_bme280 import basic as adafruit_bme280
i2c = board.I2C()  # uses board.SCL and board.SDA
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)
```

Or if you're using a SPI connection run this code instead to setup the SPI connection and sensor:

```python
import board
import digitalio
from adafruit_bme280 import basic as adafruit_bme280
spi = board.SPI()
cs = digitalio.DigitalInOut(board.D5)
bme280 = adafruit_bme280.Adafruit_BME280_SPI(spi, cs)
```

Now you're ready to read values from the sensor using any of these properties:

- **temperature** - The sensor temperature in degrees Celsius.
- **humidity** - The percent humidity as a value from 0 to 100%.
- **pressure** - The pressure in hPa.
- **altitude** - The altitude in meters.

For example to print temperature, humidity, and pressure:

```auto
print("\nTemperature: %0.1f C" % bme280.temperature)
print("Humidity: %0.1f %%" % bme280.humidity)
print("Pressure: %0.1f hPa" % bme280.pressure)

```

![](https://cdn-learn.adafruit.com/assets/assets/000/048/973/medium800/adafruit_products_bme280_1.png?1512683679)

For altitude you'll want to set the pressure at sea level for your location to get the most accurate measure (remember these sensors can only infer altitude based on pressure and need a set calibration point).&nbsp; Look at your local weather report for a pressure at sea level reading and set the **sea\_level\_pressure** &nbsp;property:

```auto
bme280.sea_level_pressure = 1013.4
```

Then read the altitude property for a more accurate altitude reading (but remember this altitude will fluctuate based on atmospheric pressure changes!):

```auto
print("Altitude = %0.2f meters" % bme280.altitude)
```

![](https://cdn-learn.adafruit.com/assets/assets/000/048/975/medium800/adafruit_products_bme280_3.png?1512683905)

You can use the BME280 temperature and humidity to calculate the dew point using the [Magnus formula](https://en.wikipedia.org/wiki/Dew_point#Calculating_the_dew_point)! For this example, you'll need to `import` an additional library: `math`. Run the following code:

```auto
import math
b = 17.62
c = 243.12
gamma = (b * bme280.temperature /(c + bme280.temperature)) + math.log(bme280.humidity / 100.0)
dewpoint = (c * gamma) / (b - gamma)
print(dewpoint)
```

That's all there is to using the BME280 sensor with CircuitPython!

# Full Example Code
https://github.com/adafruit/Adafruit_CircuitPython_BME280/blob/main/examples/bme280_simpletest.py

# LLM Agent Embodiment Kit

## VEML770

It's easy to use the VEML7700 sensor with CircuitPython and the&nbsp;[Adafruit CircuitPython VEML7700](https://github.com/adafruit/Adafruit_CircuitPython_VEML7700)&nbsp;module.&nbsp; This module allows you to easily write Python code that reads the ambient light levels, including Lux, from the sensor.

You can use this sensor with any CircuitPython microcontroller board or with a computer that has GPIO and Python&nbsp;[thanks to Adafruit\_Blinka, our CircuitPython-for-Python compatibility library](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux).

## CircuitPython Microcontroller Wiring

First wire up a VEML7700 to your board exactly as follows. Here is an example of the VEML7700 wired to a Feather using I2C:

- **Board 3V** &nbsp;to&nbsp;**sensor VIN (red wire on STEMMA QT version)**  
- **Board GND** &nbsp;to&nbsp;**sensor GND (black wire on STEMMA QT version)**  
- **Board SCL** &nbsp;to&nbsp;**sensor SCL (yellow wire on STEMMA QT version)**  
- **Board SDA** &nbsp;to&nbsp;**sensor SDA (blue wire on STEMMA QT version)**  

![adafruit_products_VEML7700QR_Feather_STEMMA_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/109/045/medium640/adafruit_products_VEML7700QR_Feather_STEMMA_bb.jpg?1645044621)

![adafruit_products_VEML7700QR_Feather_breadboard_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/109/046/medium640/adafruit_products_VEML7700QR_Feather_breadboard_bb.jpg?1645044639)

![adafruit_products_VEML7700_Feather_original.png](https://cdn-learn.adafruit.com/assets/assets/000/109/047/medium640/adafruit_products_VEML7700_Feather_original.png?1645044656)

Primary: 

## Python Computer Wiring

Since there's&nbsp;_dozens_&nbsp;of Linux computers/boards you can use we will show wiring for Raspberry Pi. For other platforms,&nbsp;[please visit the guide for CircuitPython on Linux to see whether your platform is supported](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux).&nbsp;

Here's the Raspberry Pi wired with I2C:

- **Pi 3V3** &nbsp;to&nbsp;**sensor VIN (red wire on STEMMA QT version)**  
- **Pi GND** &nbsp;to&nbsp;**sensor GND (black wire on STEMMA QT version)**  
- **Pi SCL** &nbsp;to&nbsp;**sensor SCL (yellow wire on STEMMA QT version)**  
- **Pi SDA** &nbsp;to&nbsp;**sensor SDA (blue wire on STEMMA QT version)**  

![adafruit_products_VEML7700QR_RasPi_STEMMA_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/109/048/medium640/adafruit_products_VEML7700QR_RasPi_STEMMA_bb.jpg?1645044712)

![adafruit_products_VEML7700QR_RasPi_breadboard_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/109/049/medium640/adafruit_products_VEML7700QR_RasPi_breadboard_bb.jpg?1645044818)

![adafruit_products_VEML7700_RasPi_original.jpg](https://cdn-learn.adafruit.com/assets/assets/000/109/050/medium640/adafruit_products_VEML7700_RasPi_original.jpg?1645044837)

## CircuitPython Installation of VEML7700 Library

You'll need to install the&nbsp;[Adafruit CircuitPython VEML7700](https://github.com/adafruit/Adafruit_CircuitPython_VEML7700) 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://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases).&nbsp; Our CircuitPython starter guide has [a great page on how to install the library bundle](https://learn.adafruit.com/welcome-to-circuitpython/circuitpython-libraries).

For non-express boards like the Trinket M0 or Gemma M0, you'll need to manually install the necessary libraries from the bundle:

- **adafruit\_veml7700.mpy**
- **adafruit\_bus\_device**
- **adafruit\_register**

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

Next&nbsp;[connect to the board's serial REPL&nbsp;](https://learn.adafruit.com/welcome-to-circuitpython/the-repl)so you are at the CircuitPython&nbsp; **\>\>\>** &nbsp;prompt.

## Python Installation of VEML7700 Library

You'll need to install the **Adafruit\_Blinka** library that provides the CircuitPython support in Python. This may also require enabling I2C on your platform and verifying you are running Python 3.&nbsp;[Since each platform is a little different, and Linux changes often, please visit the CircuitPython on Linux guide to get your computer ready](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux)!

Once that's done, from your command line run the following command:

- `sudo pip3 install adafruit-circuitpython-veml7700`

If your default Python is version 3 you may need to run 'pip' instead. Just make sure you aren't trying to use CircuitPython on Python 2.x, it isn't supported!

## CircuitPython & Python Usage

To demonstrate the usage of the sensor we'll initialize it and read the ambient light levels from the board's Python REPL.

Run the following code to import the necessary modules and initialize the I2C connection with the sensor:

```auto
import time
import board
import busio
import adafruit_veml7700

i2c = busio.I2C(board.SCL, board.SDA)
veml7700 = adafruit_veml7700.VEML7700(i2c)
```

Now you're ready to read values from the sensor using these properties:

- **light** - The ambient light data.
- **lux** - The light levels in Lux.

For example to print ambient light levels and lux values:

```auto
print("Ambient light:", veml7700.light)
print("Lux:", veml7700.lux)
```

![](https://cdn-learn.adafruit.com/assets/assets/000/073/774/medium800/adafruit_products_VEML7700REPLoutput.png?1553797248)

For more details, check out the [library documentation](https://circuitpython.readthedocs.io/projects/veml7700/en/latest/api.html).

That's all there is to using the VEML7700 sensor with CircuitPython!

## Full Example Code
https://github.com/adafruit/Adafruit_CircuitPython_VEML7700/blob/main/examples/veml7700_simpletest.py

# LLM Agent Embodiment Kit

## DRV2605

It's easy to use the DRV2605 controller with Python or CircuitPython, and the&nbsp;[Adafruit CircuitPython DRV2605](https://github.com/adafruit/Adafruit_CircuitPython_DRV2605) module. This module allows you to easily write Python code that controls the vibration of the motor.

You can use this sensor with any CircuitPython microcontroller board or with a computer that has GPIO and Python [thanks to Adafruit\_Blinka, our CircuitPython-for-Python compatibility library](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux).

# CircuitPython Microcontroller Wiring

First wire up a DRV2605 to your board exactly as shown on the previous pages for Arduino using an I2C connection.&nbsp; Here's an example of wiring a Feather M0 to the controller with I2C:

- **Board 3V** &nbsp;to&nbsp;**controller VIN (red wire in STEMMA QT version)**
- **Board GND** &nbsp;to&nbsp; **controller** **GND (black wire in STEMMA QT version)**
- **Board SCL** &nbsp;to&nbsp; **controller** **SCL (yellow wire in STEMMA QT version)**
- **Board SDA** &nbsp;to&nbsp; **controller** **SDA (blue wire in STEMMA QT version)**
- **Controller Motor -&nbsp;** to&nbsp;**motor negative (black wire in STEMMA QT version)**
- **Controller Motor +&nbsp;** to&nbsp;**motor positive (red wire in STEMMA QT version)**

![adafruit_products_featherStemma_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/113/389/medium640/adafruit_products_featherStemma_bb.jpg?1658418763)

![adafruit_products_featherBB_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/113/390/medium640/adafruit_products_featherBB_bb.jpg?1658418777)

![adafruit_products_m0_drv2605_bb.png](https://cdn-learn.adafruit.com/assets/assets/000/113/391/medium640/adafruit_products_m0_drv2605_bb.png?1658418802)

# Python Computer Wiring

Since there's _dozens_ of Linux computers/boards you can use we will show wiring for Raspberry Pi. For other platforms, [please visit the guide for CircuitPython on Linux to see whether your platform is supported](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux).&nbsp;

Here's the Raspberry Pi wired with I2C:

- **Pi 3V3** to **sensor VIN (red wire in STEMMA QT version)**
- **Pi GND** to **sensor GND (black wire in STEMMA QT version)**
- **Pi SCL** to **sensor SCL (yellow wire in STEMMA QT version)**
- **Pi SDA** to **sensor SDA (blue wire in STEMMA QT version)**
- **Controller Motor -&nbsp;** to&nbsp;**motor negative (black wire in STEMMA QT version)**
- **Controller Motor +&nbsp;** to&nbsp;**motor positive (red wire in STEMMA QT version)**

![adafruit_products_piBreadboard_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/113/392/medium640/adafruit_products_piBreadboard_bb.jpg?1658418948)

![adafruit_products_piStemma_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/113/393/medium640/adafruit_products_piStemma_bb.jpg?1658418972)

![adafruit_products_raspi_drv2605_i2c_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/113/394/medium640/adafruit_products_raspi_drv2605_i2c_bb.jpg?1658418989)

# CircuitPython Installation of DRV2605 Library

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

First make sure you are running the&nbsp;[latest version of Adafruit CircuitPython](../../../../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 introduction guide has&nbsp;[a great page on how to install the library bundle](../../../../welcome-to-circuitpython/circuitpython-libraries)&nbsp;for both express and non-express boards.

Remember for non-express boards like the, you'll need to manually install the necessary libraries from the bundle:

- **adafruit\_drv2605.mpy**
- **adafruit\_bus\_device**

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

Next[&nbsp;connect to the board's serial REPL](https://learn.adafruit.com/welcome-to-circuitpython/the-repl) so you are at the CircuitPython&nbsp; **\>\>\>** &nbsp;prompt.

# Python Installation of DRV2605 Library

You'll need to install the Adafruit\_Blinka library that provides the CircuitPython support in Python. This may also require enabling I2C on your platform and verifying you are running Python 3. [Since each platform is a little different, and Linux changes often, please visit the CircuitPython on Linux guide to get your computer ready](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux)!

Once that's done, from your command line run the following command:

- `sudo pip3 install adafruit-circuitpython-drv2605`

If your default Python is version 3 you may need to run 'pip' instead. Just make sure you aren't trying to use CircuitPython on Python 2.x, it isn't supported!

# CircuitPython & Python Usage

To demonstrate the usage of the board we'll initialize it and vibrate the motor using effects built-in to the DRV2605 chip.&nbsp; First run the following code to import the necessary modules and initialize the I2C connection with the controller:

```auto
import board
import busio
import adafruit_drv2605
i2c = busio.I2C(board.SCL, board.SDA)
drv = adafruit_drv2605.DRV2605(i2c)
```

Now you're ready to start vibrating the motor with different built-in effects.&nbsp; First you need to choose an effect to play based on its ID number.&nbsp; See [table 11.2 in the datasheet](http://www.adafruit.com/datasheets/DRV2605.pdf) for a list of all the effects:

![](https://cdn-learn.adafruit.com/assets/assets/000/072/594/medium800/adafruit_products_DRV_Waveforms.png?1552347698)

Each effect needs to be loaded into one of eight slots in the Waveform Sequencer:

![](https://cdn-learn.adafruit.com/assets/assets/000/073/544/medium800/adafruit_products_DRV2605_waveform_sequencer.jpg?1553215292)

You access the Waveform Sequencer by using the **sequence** property and providing an index for the slot location. To specify the effect, use the special **Effect** class provided in the library, giving it the effect number.

For example, here is how to load Effect ID No. 1 "Strong Click - 100%" into slot 0 of the sequence:

```auto
drv.sequence[0] = adafruit_drv2605.Effect(1)
```

To play the sequence of effects call the **play** function:

```auto
drv.play()
```

You should feel the motor vibrate in a sharp click!&nbsp; Every time you call the `play` function the motor will play back the sequence. Right now, that's just the click effected loaded into slot 0.

Try selecting a different effect and playing it, like the "Buzz 1 - 100%", a strong buzz, which is Effect ID 47:

```auto
drv.sequence[0] = adafruit_drv2605.Effect(47)
drv.play()
```

Try other effects to see which ones are interesting and useful in your project!

You can select multiple effects to play back at sequentially and create interesting compound effects. When you call `play`, the sequence is played until it either reaches a 0 or plays through all the slots. There's also a special `Pause` class you can use to generate a pause. You specify the pause time in seconds and it has to occupy a slot.

Let's play the two effects from above, separated by a half second pause:

```auto
drv.sequence[0] = adafruit_drv2605.Effect(1)
drv.sequence[1] = adafruit_drv2605.Pause(0.5)
drv.sequence[2] = adafruit_drv2605.Effect(47)
drv.sequence[3] = adafruit_drv2605.Effect(0)
drv.play()
```

The call to `play` is non-blocking, that is, it returns immediately and the rest of the code after that keeps running. The DRV2605 is doing the work of playing back the loaded sequence. If you ever want to stop the current playback, use the `stop` function:

```auto
drv.stop()
```

# Changing Motor Types

Finally it's uncommon but you might want to switch between using a linear resonance actuator motor or eccentric rotating mass motor.&nbsp; The small flat pancake motors like sold in the Adafruit shop are ERM motors and the library defaults to their usage.&nbsp; However you can call the `use_LRM` function to switch to configure the chip to use a LRM style motor:

```auto
drv.use_LRM()
```

You can also switch back to using an ERM style motor (the default) with the `use_ERM` function:

```auto
drv.use_ERM()
```

That's all there is to using the DRV2605 with CircuitPython!&nbsp; Happy motoring!

# Full Example Code

Here's a complete example of using the board to play the 123 effects for a half second each.&nbsp; Save this as main.py on your board and watch the REPL output to see the effect ID printed as it plays on the motor.

https://github.com/adafruit/Adafruit_CircuitPython_DRV2605/blob/main/examples/drv2605_simpletest.py

# LLM Agent Embodiment Kit

## LIS3DH

It's easy to use the LIS3DH sensor with Python or CircuitPython, and the [Adafruit CircuitPython LIS3DH](https://github.com/adafruit/Adafruit_CircuitPython_LIS3DH) module. This module allows you to easily write Python code that reads acceleration from the sensor.

You can use this sensor with any CircuitPython microcontroller board or with a computer that has GPIO and Python [thanks to Adafruit\_Blinka, our CircuitPython-for-Python compatibility library](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux).

# CircuitPython Microcontroller Wiring

First wire up a LIS3DH to your board exactly as shown on the previous pages for Arduino.&nbsp; You can use either I2C or SPI wiring, although it's recommended to use I2C for simplicity.&nbsp; Here's an example of wiring a Feather M0 or M4 to the sensor with I2C:

- **Board 3V** to **sensor Vin (red wire on STEMMA QT version)**  
- **Board GND** to **sensor GND (black wire on STEMMA QT version)**  
- **Board SCL** to **sensor SCL (yellow wire on STEMMA QT version)**  
- **Board SDA** to **sensor SDA (blue wire on STEMMA QT version)**  
- **Board D6** to **sensor INT** (or use any other free digital I/O pin)

![sensors_LIS3DH_FeatherM4_I2C_STEMMA_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/423/medium640/sensors_LIS3DH_FeatherM4_I2C_STEMMA_bb.jpg?1598550167)

![sensors_LIS3DH_FeatherM4_I2C_breadboard_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/425/medium640/sensors_LIS3DH_FeatherM4_I2C_breadboard_bb.jpg?1598550227)

![sensors_LIS3DH_original_Feather_I2C_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/426/medium640/sensors_LIS3DH_original_Feather_I2C_bb.jpg?1598550257)

And an example of a Feather M0 or M4 wired with hardware SPI:

- **Board 3V** to **sensor Vin**
- **Board GND** to **sensor GND**
- **Board SCK** to **sensor SCL**
- **Board MOSI** to **sensor SDA**
- **Board MISO** to **sensor SDO**
- **Board D5** to **sensor CS** (or use any other free digital I/O pin)
- **Board D6** to **sensor INT** (or use any other free digital I/O pin)

![sensors_LIS3DH_FeatherM4_SPI_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/427/medium640/sensors_LIS3DH_FeatherM4_SPI_bb.jpg?1598551327)

![sensors_LIS3DH_original_Feather_SPI.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/428/medium640/sensors_LIS3DH_original_Feather_SPI.jpg?1598551364)

Info: 

# Python Computer Wiring

Since there's _dozens_ of Linux computers/boards you can use we will show wiring for Raspberry Pi. For other platforms, [please visit the guide for CircuitPython on Linux to see whether your platform is supported](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux).&nbsp;

Here's the Raspberry Pi wired with I2C:

- **Pi 3V3** to **sensor Vin (red wire on STEMMA QT version)**  
- **Pi GND** to **sensor GND (black wire on STEMMA QT version)**  
- **Pi SCL** to **sensor SCL (yellow wire on STEMMA QT version)**  
- **Pi SDA** to **sensor SDA (blue wire on STEMMA QT version)**  
- **Pi GPIO6** to **sensor INT** (or use any other free digital I/O pin)

![sensors_LIS3DH_RasPi_I2C_STEMMA_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/429/medium640/sensors_LIS3DH_RasPi_I2C_STEMMA_bb.jpg?1598551534)

![sensors_LIS3DH_RasPi_I2C_breadboard_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/431/medium640/sensors_LIS3DH_RasPi_I2C_breadboard_bb.jpg?1598551610)

![sensors_LIS3DH_original_RasPi_I2C.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/432/medium640/sensors_LIS3DH_original_RasPi_I2C.jpg?1598551637)

And an example on the Raspberry Pi 3 Model B wired with SPI:

- **Pi 3V3** to **sensor Vin**
- **Pi GND** to **sensor GND**
- **Pi SCLK** to **sensor SCL**
- **Pi MOSI** to **sensor SDA**
- **Pi MISO** to **sensor SDO**
- **Pi GPIO5** to **sensor CS** (or use any other free digital I/O pin)
- **Pi GPIO6** to **sensor INT** (or use any other free digital I/O pin)

![sensors_LIS3DH_RasPi_SPI_bb.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/433/medium640/sensors_LIS3DH_RasPi_SPI_bb.jpg?1598551673)

![sensors_LIS3DH_original_RasPi_SPI.jpg](https://cdn-learn.adafruit.com/assets/assets/000/094/434/medium640/sensors_LIS3DH_original_RasPi_SPI.jpg?1598551697)

Info: 

# CircuitPython Installation of LIS3DH Library

Next you'll need to install the&nbsp;[Adafruit CircuitPython LIS3DH](https://github.com/adafruit/Adafruit_CircuitPython_LIS3DH)&nbsp;library on your CircuitPython board.

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; For example the Circuit Playground Express guide has&nbsp;[a great page on how to install the library bundle](https://learn.adafruit.com/welcome-to-circuitpython/circuitpython-libraries)&nbsp;for both express and non-express boards.

Remember for non-express boards like the Trinket M0, Gemma M0, and Feather/Metro M0 basic you'll need to manually install the necessary libraries from the bundle:

- **adafruit\_lis3dh.mpy**
- **adafruit\_bus\_device**

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

Next[&nbsp;connect to the board's serial REPL](https://learn.adafruit.com/welcome-to-circuitpython/the-repl) so you are at the CircuitPython&nbsp; **\>\>\>** &nbsp;prompt.

# Python Installation of LIS3DH Library

You'll need to install the Adafruit\_Blinka library that provides the CircuitPython support in Python. This may also require enabling I2C on your platform and verifying you are running Python 3. [Since each platform is a little different, and Linux changes often, please visit the CircuitPython on Linux guide to get your computer ready](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux)!

Once that's done, from your command line run the following command:

- `sudo pip3 install adafruit-circuitpython-lis3dh`

If your default Python is version 3 you may need to run 'pip' instead. Just make sure you aren't trying to use CircuitPython on Python 2.x, it isn't supported!

# CircuitPython & Python Usage

To demonstrate the usage of the sensor we'll initialize it and read the acceleration from the board's Python REPL.

If you're using an I2C connection run the following code to import the necessary modules and initialize the I2C connection with the sensor:

```python
import time
import board
import digitalio
import adafruit_lis3dh
i2c = board.I2C()
int1 = digitalio.DigitalInOut(board.D6)  # Set this to the correct pin for the interrupt!
lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c, int1=int1)
```

Or if you're using a SPI connection run this code instead to setup the SPI connection and sensor:

```python
import time
import board
import digitalio
import adafruit_lis3dh
spi = board.SPI()
cs = digitalio.DigitalInOut(board.D5)  # Set to appropriate CS pin!
int1 = digitalio.DigitalInOut(board.D6) # Set to correct pin for interrupt!
lis3dh = adafruit_lis3dh.LIS3DH_SPI(spi, cs, int1=int1)
```

Now you're ready to read values from the sensor using any of these properties:

- **acceleration** - The x, y, z acceleration values returned in a 3-tuple and are in m / s ^ 2.
- **shake** - Detect when the accelerometer is shaken.
- **tapped** - Detect when the accelerometer is tapped.

For example, to print acceleration:

```auto
x, y, z = lis3dh.acceleration
print(x, y, z)
```

![](https://cdn-learn.adafruit.com/assets/assets/000/059/070/medium800/sensors_FeatherM0_LIS3DH_xyz_output.png?1534107581)

To use shake, we've set the optional `shake_threshold=15`. The default is `30`, but lower numbers make it easier to get the shake response. Try the following code. Enter it into the REPL and then shake the board.

```auto
while True:
    if lis3dh.shake(shake_threshold=15):
        print("Shaken!")
```

![](https://cdn-learn.adafruit.com/assets/assets/000/059/071/medium800/sensors_LIS3DH_shake_repl_output.png?1534107933)

To use tapped, you need to use&nbsp;`lis3dh.set_tap` to tell it whether to look for a single- (`1`) or double-tap (`2`), and provide a threshold. We've chosen to look for a double tap (`2`) and set the threshold to `60`. Enter the following code into the REPL and then tap the board twice.

```auto
lis3dh.set_tap(2, 60)
while True:
    if lis3dh.tapped:
        print("Tapped!")
        time.sleep(0.01)
```

![](https://cdn-learn.adafruit.com/assets/assets/000/059/073/medium800/sensors_LIS3DH_tapped_REPL_output.png?1534110615)

That's all there is to using the LIS3DH sensor with CircuitPython!

# Full Example Code
https://github.com/adafruit/Adafruit_CircuitPython_LIS3DH/blob/main/examples/lis3dh_simpletest.py

# LLM Agent Embodiment Kit

## Assemble

![Fritzing breadboard diagram showing the components of the embodiment kit connected together](https://cdn-learn.adafruit.com/assets/assets/000/144/275/medium800/sensors_assemble_header.png?1779474849 )

The core of the assembly is the [perma-proto breadboard](https://www.adafruit.com/product/1609). The build requires soldering two rows of female headers, a handful of wires, and the piezo buzzer to the proto board.

There is some flexibility in where to put the NeoPixels, piezo buzzer, and microphone on the proto board. You need to have all of the same pin connections listed below, but you do not have to wire them in the exact same breadboard rows.

As you assemble the device, double check the placement of the components before soldering. Ensure that the pins are connected where they are supposed to be, and that the physical components have enough room to fit next to each other. I made the mistake of putting the mic too close to the end of the Feather on my first attempt and had to try again with it further away to actually fit both components.

Purple: If you are new to soldering check out the [Guide To Excellent Soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering) and the [Collin's Lab: Soldering](https://learn.adafruit.com/collins-lab-soldering) video. To solder headers, see [Erin's excellent guide](https://learn.adafruit.com/how-to-solder-headers).

## Headers
The first thing to solder are two rows of female header. One of them needs to be 4 pins shorter than the other to account for the offset keyed pins on the Feather.&nbsp;

I made my long header the full length of the breadboard. Making it one or two pins shorter on the far end, opposite from the Feather, would let the wire connecting the two GND rails fit better. On mine, it has to wrap around the ends of the header rows. Not terrible, but I'd make it a bit shorter on the next one. The Fritzing diagram image shows the shorter headers.

There should be 5 total rows of empty pins between the Feather header rows, 2 on one side of the center line and 3 on the other.

Make sure the headers are straight up and down, not angled. Use kapton or painters tape to secure them if you need. Solder 1 pin on each header row first and then flip over to examine the headers and ensure there is no tilt. It's much easier to correct any issues with only one joint soldered.

![Breadboard illustration showing the recommended female header placement. Long header is 2 pins short of the full breadboard, and short header is 4 pins shorter than that.](https://cdn-learn.adafruit.com/assets/assets/000/144/284/medium640/sensors_breadboard_headers_diagram.png?1779802203)

![Bottom side of perma-proto breadboard showing all soldered connections.](https://cdn-learn.adafruit.com/assets/assets/000/144/185/medium640/sensors_assembly_protoboard_bottom.png?1779296106)

![Adafruit perma-proto breadboard with two rows of female header, several wires, and a piezo buzzer soldered on to it.](https://cdn-learn.adafruit.com/assets/assets/000/144/276/medium640/sensors_assembly_protoboard.png?1779474963)

## Component Pins
Prepare for the main assembly by soldering male header pins on the Feather S3 Reverse TFT, PDM mic, and NeoPixel stick.

Use the female headers soldered to the proto breadboard in the previous step to hold the Feather and its pins while you solder them. Work carefully, the solder joins are close the the TFT display. Be sure not to touch the hot iron to the TFT.

For the NeoPixel stick, use tape to hold the row of 4 header pins in place while you solder them.

![NeoPixel stick, Feather S3 Reverse TFT, and PDM mic with male header pins soldered onto them](https://cdn-learn.adafruit.com/assets/assets/000/144/188/medium640/sensors_component_pins.png?1779300326)

Purple: A [helping hands](https://www.adafruit.com/product/291) or [panavise](https://www.digikey.com/en/supplier-centers/panavise) can hold the NeoPixel stick at a more convenient height and angle for soldering

## Protoboard Connections
Solder the wires for one component and test it using the minimal tests from the Individual Components sections, then move on to the next. Stopping to check each component as you complete the connections will make troubleshooting much easier if anything goes wrong.

Cut, and solder wires to make the following connections:

### PDM Mic

- Feather&nbsp; **GND** to breadboard top **black**  **GND** rail.
- Feather **3V** to breadboard top **red** power rail.
- PDM mic **3V** to top **red 3V** power rail.
- PDM mic **GND** to top **black**  **GND** rail.
- Feather **D5** to PDM mic **DAT**
- Feather **D6** to PDM mic **CLK**

After these wires are soldered plug in the Feather and PDM mic to the header. Verify with the [PDM test script](https://learn.adafruit.com/llm-agent-embodiment-kit/pdm-mic) that you can see sound level readings coming from the mic, they should get larger with louder sounds.

![Fritzing wiring diagram showing Feather S3 reverse TFT 3V connected to top rail, GND connected to top rail, D5 and D6 connected to breadboard rows near power and GND for a PDM mic connection](https://cdn-learn.adafruit.com/assets/assets/000/144/277/medium640/sensors_pdm_mic_wires.png?1779476669)

![PDM mic connected to the wires shown in previous photo](https://cdn-learn.adafruit.com/assets/assets/000/144/278/medium640/sensors_pdm_mic_wires_with_part.png?1779476717)

### NeoPixels

- Top **black GND** rail to bottom **black GND** rail.
- Feather **USB/5V** &nbsp;power pin to breadboard bottom red power rail.
- NeoPixel stick **GND** to bottom **black GND** rail.
- NeoPixel stick **5V** to bottom **red 5V** rail.
- Feather **D10** to NeoPixel stick **DIN**

After these wires are soldered, verify the connects work by using a [NeoPixel test script](https://learn.adafruit.com/llm-agent-embodiment-kit/neopixels) with the pixels initialized using pin **D10**.

![Fritzing wiring diagram showing Feather S3 reverse TFT on breadboard with USB 5V pin connected to power rail, GND rails connected together and wires for a NeoPixel stick broken out to breadboard rows](https://cdn-learn.adafruit.com/assets/assets/000/144/279/medium640/sensors_neopixel_wires_no_part.png?1779477940)

![Wiring diagram with partial NeoPixel stick shown in place connected with wires from previous photo](https://cdn-learn.adafruit.com/assets/assets/000/144/280/medium640/sensors_neopixel_wires_with_part.png?1779477980)

### Piezo Buzzer

- Feather **D9** to piezo buzzer **active** pin

The piezo's pins are interchangeable either one can be GND or active, so it doesn't matter which way round you put it. I made the legs tall enough to put the buzzer head slightly taller than the PDM mic when attached.

- Solder one leg to the top **black GND** rail.
- Solder the other leg to the row with the wire from Feather **D9**

Bend the buzzer legs underneath the protoboard after sticking them through the appropriate holes. Hold the proto board upside down with a helping hands, vise, or strategically stacked objects from your workbench. The bent legs prevent it from falling out due to gravity while soldering. Clip the excess leg parts after it is soldered.

Verify the connection is good with the [buzzer test script](https://learn.adafruit.com/llm-agent-embodiment-kit/piezo-buzzer).

![Fritzing wiring diagram showing Feather S3 reverse TFT with pin D9 connected to the active pin of a piezo buzzer](https://cdn-learn.adafruit.com/assets/assets/000/144/281/medium640/sensors_buzzer_wires_with_part.png?1779478841)

![Adafruit perma-proto breadboard with piezo buzzer soldered between a GND rail and a row connected by wire to feather pin D9](https://cdn-learn.adafruit.com/assets/assets/000/144/282/medium640/sensors_assembly_piezo.png?1779478904)

At this point the protoboard should look similar to the following photo.

![Adafruit Perma-Proto breadboard with 2 rows of female headers, various wires, and a piezo buzzer soldered onto it](https://cdn-learn.adafruit.com/assets/assets/000/144/263/medium800/sensors_assembly_protoboard.png?1779390065 )

## Haptic Motor & Driver Breakout
The haptic motor's small wires connect to the DRV2605 breakout output pins. Feed the wires up through the outside holes, loop around and put the stripped end back down into the inner hole. Solder on the bottom side of the inner holes.

- Haptic motor **black** to breakout **GND (-)**
- Haptic motor **red** to breakout **active (+)**

Stick the haptic motor to the back of the LIS3DH accelerometer. I used a small blob of sticky tack. The haptic motors come with adhesive on them under a peelable backing paper if you don't want to use tack.

The two breakouts get connected together with a small STEMMA QT cable.

![DRV2605 haptic motor driver and LIS3DH accelerometer connected with a STEMMA QT cable. The haptic motor is behind the LIS3DH](https://cdn-learn.adafruit.com/assets/assets/000/144/214/medium640/sensors_haptic_top.png?1779301700)

![DRV2605 haptic driver and LIS3DH accelerometer bottom side showing the haptic motor stuck to the bottom of the accelerometer.](https://cdn-learn.adafruit.com/assets/assets/000/144/215/medium640/sensors_haptic_bottom.png?1779301754)

## STEMMA QT Connections
The remaining components are all connected together with STEMMA QT cables. The chain of connected breakouts should go like this:

Feather -\> BME280 -\> VEML770 -\> DRV2605 -\> LIS3DH

With the breakouts all connected, loop them around and position the VEML7700 light sensor in front of the NeoPixel stick.

![Adafruit Feather ESP32S3 Reverse TFT connected with STEMMA QT cables to a BME280, VEML770, DRV2605, and LIS3DH](https://cdn-learn.adafruit.com/assets/assets/000/144/253/medium640/sensors_stemma_qt_chain.png?1779386783)

With everything assembled the kit should look like this.

![Feather S3 reverse TFT on a perma proto breadboard with a PDM mic, piezo buzzer, and NeoPixel stick. A STEMMA QT cable connects the feather to a BME280, VEML770, DRV2605, and LIS3DH. A cute happy face is displayed on the Feather's TFT](https://cdn-learn.adafruit.com/assets/assets/000/144/254/medium800/sensors_full_build.png?1779386817 )

# LLM Agent Embodiment Kit

## Install CircuitPython

[CircuitPython](https://github.com/adafruit/circuitpython) is a derivative of [MicroPython](https://micropython.org) designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the **CIRCUITPY** drive to iterate.

## CircuitPython Quickstart

Follow this step-by-step to quickly get CircuitPython running on your board.

[Download the latest version of CircuitPython for this board via circuitpython.org](https://circuitpython.org/board/adafruit_feather_esp32s3_reverse_tft/)
 **Click the link above to download the latest CircuitPython UF2 file.**

Save it wherever is convenient for you.

![install_circuitpython_on_most_boards_CircuitPython_downloaded.jpg](https://cdn-learn.adafruit.com/assets/assets/000/102/129/medium640/install_circuitpython_on_most_boards_CircuitPython_downloaded.jpg?1620922559)

![](https://cdn-learn.adafruit.com/assets/assets/000/119/387/medium800/adafruit_products_resetWithNeo.jpg?1678478978)

Plug your board into your computer, using a known-good data-sync cable, directly, or via an adapter if needed.

Double-click the **reset** button (highlighted in red above), and you will see the **RGB status LED(s)** turn green (highlighted in green above). If you see red, try another port, or if you're using an adapter or hub, try without the hub, or different adapter or hub.

For this board, tap reset and wait for the LED to turn purple, and as soon as it turns purple, tap reset again. The second tap needs to happen while the LED is still purple.

If double-clicking doesn't work the first time, try again. Sometimes it can take a few tries to get the rhythm right!

A lot of people end up using charge-only USB cables and it is very frustrating! **Make sure you have a USB cable you know is good for data sync.**

You will see a new disk drive appear called **FTHRS3BOOT**.

&nbsp;

Drag the **adafruit\_circuitpython\_etc.uf2** file to **FTHRS3BOOT**.

![adafruit_products_s3Boot.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/996/medium640/adafruit_products_s3Boot.jpg?1677603548)

![adafruit_products_copyTos3.jpg](https://cdn-learn.adafruit.com/assets/assets/000/118/997/medium640/adafruit_products_copyTos3.jpg?1677603564)

The **BOOT** drive will disappear and a new disk drive called **CIRCUITPY** will appear.

That's it!

![install_circuitpython_on_most_boards_CIRCUITPY.jpg](https://cdn-learn.adafruit.com/assets/assets/000/102/130/medium640/install_circuitpython_on_most_boards_CIRCUITPY.jpg?1620923145)

# LLM Agent Embodiment Kit

## 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.

# LLM Agent Embodiment Kit

## Use With Adafruit IO

## CircuitPython Code

To use the application, you need to obtain&nbsp; **code.py** with the program, and the other project files to place on the Feather **CIRCUITPY** drive.

Thankfully, this can be done in one go. In the example below, click the **Download Project Bundle** button below to download the necessary libraries, the **code.py** file, and other project files in a zip file.

Connect your board to your computer via a known good data+power USB cable. The board should show up in your File Explorer/Finder (depending on your operating system) as a flash drive named **CIRCUITPY**.

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

## Drive Structure

Extract the contents of the zip file, copy the **lib** directory files to **CIRCUITPY/lib**. Copy the **code.py** , and **embodiment\_message\_handler.py** files, as well as the&nbsp; **embodiment\_kit/** &nbsp;folder to your **CIRCUITPY** drive.

After copying the files, your drive should look like the listing below. It can contain other files as well, but must contain these at a minimum.

![CIRCUITPY drive screenshot showing required project files and libraries](https://adafruit.github.io/Adafruit_Learning_System_Guides/Embodiment_Kit_circuitpython_code_httpserver.png )

## CLI Script

The Adafruit IO version of the microcontroller code subscribes to the feed&nbsp;`embodiment.client-to-mcu` on Adafruit IO and waits for commands to be received. It executes commands as they come in and responds in the feed&nbsp;`embodiment.mcu-to-client`. Follow the instructions on the [IO Feed Setup](https://learn.adafruit.com/llm-agent-embodiment-kit/io-feed-setup) page to create the feeds. Commands and responses are sent as JSON objects inside of these feeds.

A CLI script is provided to conveniently send commands to the AIO feed from a terminal. It accepts various arguments to specify and configure the commands. This script can be used on its own to integrate the embodiment kit hardware in non-LLM agent contexts as well.

The script expects to find environment variables with AIO credentials.

You must have:

- `ADAFRUIT_AIO_USERNAME` - set to your AIO username.
- `ADAFRUIT_AIO_KEY` - set to your AIO token.

On Linux based OS's you can use the `export` command to set environment variables.

```terminal
export ADAFRUIT_AIO_USERNAME="your_username"
export ADAFRUIT_AIO_KEY="aio_secrettoken1234"
```

Here is the `--help` output from the CLI script:

```terminal
$ python embodiment_cli.py --help
usage: embodiment_cli.py [-h] [-t TIMEOUT] [-q] [--commandlist] [command] [key=value ...]

Send a command to the embodiment MCU and wait for ack. Output response JSON.

positional arguments:
  command               Name of the command to send (e.g. show_squinch_face).
  key=value             Optional arguments as key=value pairs (e.g. frequency=440 duration=0.5).

options:
  -h, --help            show this help message and exit
  -t TIMEOUT, --timeout TIMEOUT
                        Seconds to wait for ack (default: 10, or 22 for show_prompt).
  -q, --quiet           Suppress connection/status logging; only print the ack response.
  --commandlist         Print available commands and their arguments, then exit.
```

### CLI Script Code
https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/Embodiment_Kit/agent_skill/embodiment-kit/scripts/embodiment_cli.py

## Agent Skill

An agent skill provides details about the hardware, and instructions on how to use the CLI. It contains information about capabilities and common use cases. The main file for the skill is a plaintext markdown file so it is easy to modify if you want to expand the capabilities or define more specific use cases that fit into your workflows.

![Terminal output showing successful results of hardware diagnostics check run by an LLM agent using the embodiment kit.](https://cdn-learn.adafruit.com/assets/assets/000/144/262/medium800/sensors_skill_test_results.png?1779389686 )

Click the **embodiment-kit.zip** button to download a zipped copy of the skill folder.

Unzip it place it inside of skills directory for you agent harness. The skills directory for Claude Code is&nbsp;`~/.claude/skills/`. So for CC the full location of the skill would be `~/.claude/skills/embodiment-kit/`. Consult the docs for your harness if you use a different one.

Danger: Always review the content of **SKILL.md**, and other bundled files before installing an agent skill.

[embodiment-kit.zip](https://cdn-learn.adafruit.com/assets/assets/000/144/266/original/embodiment-kit.zip?1779393025)
Here is the **SKILL.md** file, it's also included in the downloaded skill zip.

```ruby
---
name: embodiment-kit
description: Interact with a physical embodiment kit microcontroller located in the user's room. Send commands to control a display (faces, messages, prompts), NeoPixel lights, a piezo buzzer, and a vibration motor — and to read sensors (temperature, humidity, pressure, ambient lux, microphone, accelerometer). Use to answer questions about the physical environment and to express status, get the human's attention, or communicate visually/audibly/haptically in the room.
metadata:
  version: "1.1"
  requires: ["python3", "either (ADAFRUIT_AIO_USERNAME + ADAFRUIT_AIO_KEY env vars) or (EMBODIMENT_KIT_HOST env var)"]
---

# Embodiment Kit Skill

This skill lets you read sensors from and drive actuators on a physical embodiment kit microcontroller located in the user's room. Every command round-trips and returns a JSON ack containing the current sensor readings and output state — and, for actuator commands, a `proof` block with before/after sensor readings that confirm the action had a physical effect.

## When to Use This Skill

Use this skill when you need to:

- **Sense the room**: answer questions about the current temperature, humidity, pressure, ambient light, sound level, or device orientation.
- **Express into the room**: signal status, completion, attention, or mood using the display, lights, buzzer, or vibration motor.
- **Interact with the human**: display a message they should read, or pose a multiple-choice question and wait for a button press.
- **Verify physical effects**: confirm an actuator actually fired by reading the `proof` block in the ack.

Choose actuators thoughtfully — these produce real light, sound, and motion in the human's room. Avoid firing them gratuitously or when the human may be sleeping/focused unless they've asked for it.

## Requirements

- Python virtual environment with `requests` installed.
- If using the Adafruit IO transport (see below), also need installed:
  - `adafruit-circuitpython-adafruitio`
  - `adafruit-circuitpython-connectionmanager`
  - `adafruit-circuitpython-minimqtt`
- One of the two transports below must be configured via environment variables.
- CLI script at `<skills_directory>/embodiment-kit/scripts/embodiment_cli.py`.

### Transports

The CLI supports two ways of reaching the device. Set one (the CLI prefers HTTP when both are present):

- **Direct HTTP (recommended for same-network use)**: set `EMBODIMENT_KIT_HOST` to the device's URL or hostname, e.g. `http://192.168.1.189:5000` or `embodiment.local:5000`. A scheme is optional; `http://` is assumed if missing. Port `5000` is default. The CLI POSTs the command JSON to `<host>/embodiment_kit` and reads the ack from the HTTP response — no MQTT broker or Adafruit account needed. This is the lowest-latency option and works fully offline from the public internet.
- **Adafruit IO MQTT (for remote / cross-network use)**: set both `ADAFRUIT_AIO_USERNAME` and `ADAFRUIT_AIO_KEY`. The CLI publishes the command on the `embodiment.client-to-mcu` feed and waits for the ack on `embodiment.mcu-to-client`. Use this when you cannot reach the device directly on the local network.

If neither transport's env vars are set, the CLI exits with an error before sending anything.

## How to Run a Command

General form:

```bash
python <skills_directory>/embodiment-kit/scripts/embodiment_cli.py <command> [key=value ...] [-t TIMEOUT] [-q]
```

- `key=value` arguments are parsed as JSON when possible. Integers like `0xff8800` are parsed as hex. Strings with spaces should be quoted at the shell level (`message="Hello world"`).
- `-q` / `--quiet` suppresses connection logging on stderr, leaving stdout as pure JSON suitable for piping into `jq` or `json.loads`.
- Default timeout is 10s (22s for `show_prompt`). Override with `-t SECONDS`.
- `--commandlist` prints the full command reference from `embodiment_cli_help.md`.

Every successful response is a single line of JSON on stdout, parseable directly:

```json
{
  "state": {
    "sensors": { "...": "current readings" },
    "outputs": { "neopixels": {}, "display": "..." }
  },
  "metadata": { "type": "ack", "proof": {} },
  "command": { "name": "...", "uuid": "...", "arguments": {} }
}
```

The `metadata.proof` field is only present on actuator commands. To consume the output programmatically, pipe through `jq` or read it with `json.loads`:

```bash
python embodiment_cli.py get_data -q | jq '.state.sensors.temperature'
python embodiment_cli.py get_data -q | python -c "import sys, json; print(json.load(sys.stdin)['state']['sensors']['temperature'])"
```

## Sensors (always returned in every ack)

Under `state.sensors`:

- `temperature` — degrees C
- `humidity` — percent
- `pressure` — hPa
- `lux` — ambient light
- `pdm_mic` — normalized RMS sound magnitude
- `accelerometer` — string `"x=<x>, y=<y>, z=<z> G"`, averaged over 10 samples. A device sitting flat reads roughly `z≈9.8`.

### `get_data`
Returns the standard ack with no side effects. Use to answer questions about the room's current state.

```bash
python embodiment_cli.py get_data
```

## Display Face Commands

### Preset Faces
- `show_happy_face`
- `show_sad_face`
- `show_angry_face`
- `show_confused_face`
- `show_sleepy_face`

Shows the specified preset face. Optional `background_color` (24-bit RGB int, default `0x88ddff`).

```bash
python embodiment_cli.py show_happy_face
python embodiment_cli.py show_happy_face background_color=0xffcc00
python embodiment_cli.py show_sleepy_face
python embodiment_cli.py show_sleepy_face background_color=0xffcc00
```

### `show_custom_face`
Build a face from layer choices. First call `list_custom_face_options` to see valid filenames for each layer (`eyebrows`, `eyes`, `blush`, `mouth`). Each layer is a `[filename, y_offset]` pair. The y_offset is relative to the center of the screen. Negative values move the sprite up, positive values move it down. The display height is only 135px, offset values should be within the range -50 to 50 in order to keep them visible.

```bash
python embodiment_cli.py list_custom_face_options
python embodiment_cli.py show_custom_face options='{"eyes":["round_eyes_happy.png",-20],"mouth":["mouth_smiling.png",60]}'
```

## Display Message Commands

### `show_message` — important formatting rules
Hides the face and displays text.

**Display constraints — the screen fits at most 5 rows of 19 characters per row.** Plan messages around this:

- Keep each line ≤ 19 characters. Longer lines will be cut off.
- Use at most 5 lines total. Additional lines will not render.
- Use `\n` (literal backslash-n in the shell argument) to break lines manually — do NOT rely on auto-wrapping.
- Prefer short, scannable phrasing over paragraphs. Abbreviate when needed.

```bash
python embodiment_cli.py show_message message="Build passed\nReady to deploy"
python embodiment_cli.py show_message message="Tests: 42/42 OK\nLint: clean\nCoverage: 87%"
```

Bad (too long per line, will be truncated):

```bash
# DON'T: 23 chars on line 1, no newlines — will overflow / wrap unpredictably
python embodiment_cli.py show_message message="The deployment finished successfully a moment ago"
```

### `show_prompt` — important formatting rules
Displays a message and waits for the human to press one of three hardware buttons (`D0`, `D1`, `D2`) or time out.

**Same display constraints as `show_message`: 5 rows × 19 chars.** Use them to your advantage by structuring the prompt as a question followed by labeled options on their own lines.

Recommended structure: question on line 1, then up to three options on the remaining lines, each labeled with the button index that selects it (`0)`, `1)`, `2)`):

```bash
python embodiment_cli.py show_prompt message="Deploy now?\n0) Yes\n1) No\n2) Later" timeout=30
python embodiment_cli.py show_prompt message="Mood?\n0) Good\n1) OK\n2) Tired"
```

Arguments:
- `message` (string, default `"Press a button"`).
- `timeout` (seconds, default `20`). If you set this, the CLI's own ack-timeout (`-t`) is auto-bumped to `timeout + 2`. If you override both, `-t` must be strictly greater than `timeout`.

The ack's `command.response.prompt_result` will be one of:
- `"btn D0 pressed"` → option 0 chosen
- `"btn D1 pressed"` → option 1 chosen
- `"btn D2 pressed"` → option 2 chosen
- `"timed out"` → no press before timeout

Map the button → option by the labels you wrote in the message. After a press the display briefly shows `"Thank you"`; on timeout it shows `"Prompt timed out"`.

Tips:
- Only three buttons exist — never offer more than three options.
- Keep option labels very short (e.g. `Yes`, `No`, `Later`) so the `N) label` line fits in 19 chars.
- If asking a yes/no question, you can use 2 options and leave the third button unused.
- Pick a `timeout` long enough that the human can read and decide, but not so long that the prompt blocks the conversation indefinitely (20–60s is usually right).

## Light Commands (NeoPixel strip)

### `lights_on`
Turns on the strip. `color` is a 24-bit RGB int (default magenta `0xff00ff`). `brightness` is 0.0–1.0 (default is the current brightness).

```bash
python embodiment_cli.py lights_on color=0x00ff00 brightness=0.4
```

Proof block: `idle_lux_level` vs `on_lux_level` (lux should rise).

### `lights_off`
Fills the strip with black.

```bash
python embodiment_cli.py lights_off
```

Proof block: `idle_lux_level` vs `off_lux_level` (lux should drop).

## Sound Command

### `play_tone`
Plays a tone on the piezo buzzer.

- `frequency` (Hz, default `440`)
- `duty_cycle` (default `2**15` ≈ 50%)
- `duration` (seconds, default `0.5`, **max `3`**)

```bash
python embodiment_cli.py play_tone frequency=523 duration=0.8
```

Proof block: `idle_sound_level` vs `playing_sound_level` (mic RMS should rise).

## Haptic Command

### `vibrate`
Runs the vibration motor for ~0.75 s. No arguments.

```bash
python embodiment_cli.py vibrate
```

Proof block: `idle_z_acceleration` vs `vibrating_z_acceleration` (Z-axis acceleration usually decreases during vibration).

## Patterns for Expressing Status

Some useful patterns for using actuators meaningfully:

- **Task complete, low-key**: `show_message message="Done"` or a brief `play_tone frequency=880 duration=0.2`.
- **Task complete, celebratory**: `show_happy_face` + `lights_on color=0x00ff00 brightness=0.5`, then `lights_off` a few seconds later.
- **Need attention**: `vibrate` + `show_message` describing what you need.
- **Error / warning**: `lights_on color=0xff0000 brightness=0.7` + `show_message message="Build failed\nsee terminal"`.
- **Ask the human a question**: `show_prompt` with a short question and 2–3 labeled options.
- **Ambient status indicator**: `lights_on` with a color encoding state (e.g. blue=working, green=done, red=blocked), turn off when state ends.

Always pair attention-grabbing actuators (sound, vibration, bright lights) with a display message that explains *why* you grabbed attention, so the human knows what to do next. Clean up after yourself — turn lights off when the signal is no longer relevant.

## Reference Files

- `embodiment_cli.py` — the CLI itself.
- `embodiment_cli_help.md` — the canonical command reference (also printable via `--commandlist`).
- `embodiment_message_handler.py`, `code_mcu_mqtt.py`, `code_mcu_httpserver.py` — MCU-side firmware (for context, not invoked from this skill).
```

# LLM Agent Embodiment Kit

## IO Feed Setup

If you're using the Adafruit IO version of the CircuitPython code, you will need to set up two feeds under a group in your AIO account.

## Create Group
Log in to [Adafruit IO](https://io.adafruit.com/) and go to the dashboard.

Click on&nbsp; **Feeds** and then click the **New Group** button.

Enter the name "Embodiment" for the new group.

Click the **Create** button.

![Adafruit IO page with Feeds navigation link, and New Group button highlighted.](https://cdn-learn.adafruit.com/assets/assets/000/144/257/medium640/sensors_aio_new_group.png?1779388164)

![Adafruit IO create group dialog with "Embodiment" entered into the name field.](https://cdn-learn.adafruit.com/assets/assets/000/144/258/medium640/sensors_aio_new_group_name.png?1779388219)

## Create Feeds
Click on the **New Feed** button.

Enter "client\_to\_mcu" as the new feed name and press the **Create** button.

Click **New Feed** again to create a second feed.

Enter "mcu\_to\_client" as the second feed name and press the **Create** button.

![Adafruit IO group page with the New Feed button highlighted.](https://cdn-learn.adafruit.com/assets/assets/000/144/259/medium640/sensors_aio_new_feed.png?1779388609)

![Create feed dialog with "client_to_mcu" entered for the new feed name](https://cdn-learn.adafruit.com/assets/assets/000/144/260/medium640/sensors_aio_feed_client_to_mcu.png?1779388733)

![Create feed dialog with "client_to_mcu" entered for the new feed name](https://cdn-learn.adafruit.com/assets/assets/000/144/261/medium640/sensors_aio_feed_mcu_to_client.png?1779388753)

## Disable History
The mcu\_to\_client feed needs to have its history disabled in order to raise the message size limit.

Click on the mcu\_to\_client feed to go into it, scroll down a little and click on the gear in the Feed History section.

Select **Off** in the feed history setting dropdown and click **Save**.

![Adafruit IO Feed page for mcu_to_client feed with the Feed History section highlighted in the right column](https://cdn-learn.adafruit.com/assets/assets/000/144/264/medium640/sensors_history_settings.png?1779390556)

![Feed history dialog showing feed history set to Off](https://cdn-learn.adafruit.com/assets/assets/000/144/265/medium640/sensors_feed_history_off.png?1779390581)

# LLM Agent Embodiment Kit

## Use With HTTPServer

## CircuitPython Code

To use the application, you need to obtain&nbsp; **code.py** with the program, and the other project files to place on the Feather **CIRCUITPY** drive.

Thankfully, this can be done in one go. In the example below, click the **Download Project Bundle** button below to download the necessary libraries, the **code.py** file, and other project files in a zip file.

Connect your board to your computer via a known good data+power USB cable. The board should show up in your File Explorer/Finder (depending on your operating system) as a flash drive named **CIRCUITPY**.

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

## Drive Structure

Extract the contents of the zip file, copy the **lib** directory files to **CIRCUITPY/lib**. Copy the **code.py** , and **embodiment\_message\_handler.py** files, as well as the&nbsp; **embodiment\_kit/** &nbsp;folder to your **CIRCUITPY** drive.

After copying the files, your drive should look like the listing below. It can contain other files as well, but must contain these at a minimum.

![CIRCUITPY drive screenshot showing required project files and libraries](https://adafruit.github.io/Adafruit_Learning_System_Guides/Embodiment_Kit_circuitpython_code_httpserver.png )

## CLI Script

The HTTPServer version of the microcontroller code listens with a web-server on port&nbsp;`5000` on the local network. Commands are sent as POST requests with JSON in the body to the `/embodiment_kit` endpoint.&nbsp;

A CLI script is provided to conveniently send command requests to local web-server. It accepts various arguments to specify and configure the commands. This script can be used on its own to integrate the embodiment kit hardware in non-LLM agent contexts as well.

The CLI script expects to find an environment variable with a URL to a local device.

You must have:

- `EMBODIMENT_KIT_HOST` - set to the IP or URL to your device like `192.168.1.188:5000` or `cpy-s3_reverse_tft-dc5475f05af8.local:5000`.

On Linux based OS's you can use the `export` command to set environment variables.

```terminal
export EMBODIMENT_KIT_HOST="192.168.1.188:5000"
```

Here is the `--help` output from the CLI script:

```terminal
$ python embodiment_cli.py --help
usage: embodiment_cli.py [-h] [-t TIMEOUT] [-q] [--commandlist] [command] [key=value ...]

Send a command to the embodiment MCU and wait for ack. Output response JSON.

positional arguments:
  command               Name of the command to send (e.g. show_squinch_face).
  key=value             Optional arguments as key=value pairs (e.g. frequency=440 duration=0.5).

options:
  -h, --help            show this help message and exit
  -t TIMEOUT, --timeout TIMEOUT
                        Seconds to wait for ack (default: 10, or 22 for show_prompt).
  -q, --quiet           Suppress connection/status logging; only print the ack response.
  --commandlist         Print available commands and their arguments, then exit.
```

### CLI Script Code
https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/Embodiment_Kit/agent_skill/embodiment-kit/scripts/embodiment_cli.py

## Agent Skill
An agent skill provides details about the hardware, and instructions on how to use the CLI. It contains information about capabilities and common use cases. The main file for the skill is a plaintext markdown file so it is easy to modify if you want to expand the capabilities or define more specific use cases that fit into your workflows.

![Terminal output showing successful results of hardware diagnostics check run by an LLM agent using the embodiment kit.](https://cdn-learn.adafruit.com/assets/assets/000/144/262/medium800/sensors_skill_test_results.png?1779389686 )

Click the **embodiment-kit.zip** button to download a zipped copy of the skill folder.

Unzip it place it inside of skills directory for you agent harness. The skills directory for Claude Code is&nbsp;`~/.claude/skills/`. So for CC the full location of the skill would be `~/.claude/skills/embodiment-kit/`. Consult the docs for your harness if you use a different one.

Danger: Always review the content of **SKILL.md**, and other bundled files before installing an agent skill.

[embodiment-kit.zip](https://cdn-learn.adafruit.com/assets/assets/000/144/266/original/embodiment-kit.zip?1779393025)
Here is the **SKILL.md** file, it's also included in the downloaded skill zip.

```ruby
---
name: embodiment-kit
description: Interact with a physical embodiment kit microcontroller located in the user's room. Send commands to control a display (faces, messages, prompts), NeoPixel lights, a piezo buzzer, and a vibration motor — and to read sensors (temperature, humidity, pressure, ambient lux, microphone, accelerometer). Use to answer questions about the physical environment and to express status, get the human's attention, or communicate visually/audibly/haptically in the room.
metadata:
  version: "1.1"
  requires: ["python3", "either (ADAFRUIT_AIO_USERNAME + ADAFRUIT_AIO_KEY env vars) or (EMBODIMENT_KIT_HOST env var)"]
---

# Embodiment Kit Skill

This skill lets you read sensors from and drive actuators on a physical embodiment kit microcontroller located in the user's room. Every command round-trips and returns a JSON ack containing the current sensor readings and output state — and, for actuator commands, a `proof` block with before/after sensor readings that confirm the action had a physical effect.

## When to Use This Skill

Use this skill when you need to:

- **Sense the room**: answer questions about the current temperature, humidity, pressure, ambient light, sound level, or device orientation.
- **Express into the room**: signal status, completion, attention, or mood using the display, lights, buzzer, or vibration motor.
- **Interact with the human**: display a message they should read, or pose a multiple-choice question and wait for a button press.
- **Verify physical effects**: confirm an actuator actually fired by reading the `proof` block in the ack.

Choose actuators thoughtfully — these produce real light, sound, and motion in the human's room. Avoid firing them gratuitously or when the human may be sleeping/focused unless they've asked for it.

## Requirements

- Python virtual environment with `requests` installed.
- If using the Adafruit IO transport (see below), also need installed:
  - `adafruit-circuitpython-adafruitio`
  - `adafruit-circuitpython-connectionmanager`
  - `adafruit-circuitpython-minimqtt`
- One of the two transports below must be configured via environment variables.
- CLI script at `<skills_directory>/embodiment-kit/scripts/embodiment_cli.py`.

### Transports

The CLI supports two ways of reaching the device. Set one (the CLI prefers HTTP when both are present):

- **Direct HTTP (recommended for same-network use)**: set `EMBODIMENT_KIT_HOST` to the device's URL or hostname, e.g. `http://192.168.1.189:5000` or `embodiment.local:5000`. A scheme is optional; `http://` is assumed if missing. Port `5000` is default. The CLI POSTs the command JSON to `<host>/embodiment_kit` and reads the ack from the HTTP response — no MQTT broker or Adafruit account needed. This is the lowest-latency option and works fully offline from the public internet.
- **Adafruit IO MQTT (for remote / cross-network use)**: set both `ADAFRUIT_AIO_USERNAME` and `ADAFRUIT_AIO_KEY`. The CLI publishes the command on the `embodiment.client-to-mcu` feed and waits for the ack on `embodiment.mcu-to-client`. Use this when you cannot reach the device directly on the local network.

If neither transport's env vars are set, the CLI exits with an error before sending anything.

## How to Run a Command

General form:

```bash
python <skills_directory>/embodiment-kit/scripts/embodiment_cli.py <command> [key=value ...] [-t TIMEOUT] [-q]
```

- `key=value` arguments are parsed as JSON when possible. Integers like `0xff8800` are parsed as hex. Strings with spaces should be quoted at the shell level (`message="Hello world"`).
- `-q` / `--quiet` suppresses connection logging on stderr, leaving stdout as pure JSON suitable for piping into `jq` or `json.loads`.
- Default timeout is 10s (22s for `show_prompt`). Override with `-t SECONDS`.
- `--commandlist` prints the full command reference from `embodiment_cli_help.md`.

Every successful response is a single line of JSON on stdout, parseable directly:

```json
{
  "state": {
    "sensors": { "...": "current readings" },
    "outputs": { "neopixels": {}, "display": "..." }
  },
  "metadata": { "type": "ack", "proof": {} },
  "command": { "name": "...", "uuid": "...", "arguments": {} }
}
```

The `metadata.proof` field is only present on actuator commands. To consume the output programmatically, pipe through `jq` or read it with `json.loads`:

```bash
python embodiment_cli.py get_data -q | jq '.state.sensors.temperature'
python embodiment_cli.py get_data -q | python -c "import sys, json; print(json.load(sys.stdin)['state']['sensors']['temperature'])"
```

## Sensors (always returned in every ack)

Under `state.sensors`:

- `temperature` — degrees C
- `humidity` — percent
- `pressure` — hPa
- `lux` — ambient light
- `pdm_mic` — normalized RMS sound magnitude
- `accelerometer` — string `"x=<x>, y=<y>, z=<z> G"`, averaged over 10 samples. A device sitting flat reads roughly `z≈9.8`.

### `get_data`
Returns the standard ack with no side effects. Use to answer questions about the room's current state.

```bash
python embodiment_cli.py get_data
```

## Display Face Commands

### Preset Faces
- `show_happy_face`
- `show_sad_face`
- `show_angry_face`
- `show_confused_face`
- `show_sleepy_face`

Shows the specified preset face. Optional `background_color` (24-bit RGB int, default `0x88ddff`).

```bash
python embodiment_cli.py show_happy_face
python embodiment_cli.py show_happy_face background_color=0xffcc00
python embodiment_cli.py show_sleepy_face
python embodiment_cli.py show_sleepy_face background_color=0xffcc00
```

### `show_custom_face`
Build a face from layer choices. First call `list_custom_face_options` to see valid filenames for each layer (`eyebrows`, `eyes`, `blush`, `mouth`). Each layer is a `[filename, y_offset]` pair. The y_offset is relative to the center of the screen. Negative values move the sprite up, positive values move it down. The display height is only 135px, offset values should be within the range -50 to 50 in order to keep them visible.

```bash
python embodiment_cli.py list_custom_face_options
python embodiment_cli.py show_custom_face options='{"eyes":["round_eyes_happy.png",-20],"mouth":["mouth_smiling.png",60]}'
```

## Display Message Commands

### `show_message` — important formatting rules
Hides the face and displays text.

**Display constraints — the screen fits at most 5 rows of 19 characters per row.** Plan messages around this:

- Keep each line ≤ 19 characters. Longer lines will be cut off.
- Use at most 5 lines total. Additional lines will not render.
- Use `\n` (literal backslash-n in the shell argument) to break lines manually — do NOT rely on auto-wrapping.
- Prefer short, scannable phrasing over paragraphs. Abbreviate when needed.

```bash
python embodiment_cli.py show_message message="Build passed\nReady to deploy"
python embodiment_cli.py show_message message="Tests: 42/42 OK\nLint: clean\nCoverage: 87%"
```

Bad (too long per line, will be truncated):

```bash
# DON'T: 23 chars on line 1, no newlines — will overflow / wrap unpredictably
python embodiment_cli.py show_message message="The deployment finished successfully a moment ago"
```

### `show_prompt` — important formatting rules
Displays a message and waits for the human to press one of three hardware buttons (`D0`, `D1`, `D2`) or time out.

**Same display constraints as `show_message`: 5 rows × 19 chars.** Use them to your advantage by structuring the prompt as a question followed by labeled options on their own lines.

Recommended structure: question on line 1, then up to three options on the remaining lines, each labeled with the button index that selects it (`0)`, `1)`, `2)`):

```bash
python embodiment_cli.py show_prompt message="Deploy now?\n0) Yes\n1) No\n2) Later" timeout=30
python embodiment_cli.py show_prompt message="Mood?\n0) Good\n1) OK\n2) Tired"
```

Arguments:
- `message` (string, default `"Press a button"`).
- `timeout` (seconds, default `20`). If you set this, the CLI's own ack-timeout (`-t`) is auto-bumped to `timeout + 2`. If you override both, `-t` must be strictly greater than `timeout`.

The ack's `command.response.prompt_result` will be one of:
- `"btn D0 pressed"` → option 0 chosen
- `"btn D1 pressed"` → option 1 chosen
- `"btn D2 pressed"` → option 2 chosen
- `"timed out"` → no press before timeout

Map the button → option by the labels you wrote in the message. After a press the display briefly shows `"Thank you"`; on timeout it shows `"Prompt timed out"`.

Tips:
- Only three buttons exist — never offer more than three options.
- Keep option labels very short (e.g. `Yes`, `No`, `Later`) so the `N) label` line fits in 19 chars.
- If asking a yes/no question, you can use 2 options and leave the third button unused.
- Pick a `timeout` long enough that the human can read and decide, but not so long that the prompt blocks the conversation indefinitely (20–60s is usually right).

## Light Commands (NeoPixel strip)

### `lights_on`
Turns on the strip. `color` is a 24-bit RGB int (default magenta `0xff00ff`). `brightness` is 0.0–1.0 (default is the current brightness).

```bash
python embodiment_cli.py lights_on color=0x00ff00 brightness=0.4
```

Proof block: `idle_lux_level` vs `on_lux_level` (lux should rise).

### `lights_off`
Fills the strip with black.

```bash
python embodiment_cli.py lights_off
```

Proof block: `idle_lux_level` vs `off_lux_level` (lux should drop).

## Sound Command

### `play_tone`
Plays a tone on the piezo buzzer.

- `frequency` (Hz, default `440`)
- `duty_cycle` (default `2**15` ≈ 50%)
- `duration` (seconds, default `0.5`, **max `3`**)

```bash
python embodiment_cli.py play_tone frequency=523 duration=0.8
```

Proof block: `idle_sound_level` vs `playing_sound_level` (mic RMS should rise).

## Haptic Command

### `vibrate`
Runs the vibration motor for ~0.75 s. No arguments.

```bash
python embodiment_cli.py vibrate
```

Proof block: `idle_z_acceleration` vs `vibrating_z_acceleration` (Z-axis acceleration usually decreases during vibration).

## Patterns for Expressing Status

Some useful patterns for using actuators meaningfully:

- **Task complete, low-key**: `show_message message="Done"` or a brief `play_tone frequency=880 duration=0.2`.
- **Task complete, celebratory**: `show_happy_face` + `lights_on color=0x00ff00 brightness=0.5`, then `lights_off` a few seconds later.
- **Need attention**: `vibrate` + `show_message` describing what you need.
- **Error / warning**: `lights_on color=0xff0000 brightness=0.7` + `show_message message="Build failed\nsee terminal"`.
- **Ask the human a question**: `show_prompt` with a short question and 2–3 labeled options.
- **Ambient status indicator**: `lights_on` with a color encoding state (e.g. blue=working, green=done, red=blocked), turn off when state ends.

Always pair attention-grabbing actuators (sound, vibration, bright lights) with a display message that explains *why* you grabbed attention, so the human knows what to do next. Clean up after yourself — turn lights off when the signal is no longer relevant.

## Reference Files

- `embodiment_cli.py` — the CLI itself.
- `embodiment_cli_help.md` — the canonical command reference (also printable via `--commandlist`).
- `embodiment_message_handler.py`, `code_mcu_mqtt.py`, `code_mcu_httpserver.py` — MCU-side firmware (for context, not invoked from this skill).
```


## Featured Products

### Adafruit ESP32-S3 Reverse TFT Feather

[Adafruit ESP32-S3 Reverse TFT Feather](https://www.adafruit.com/product/5691)
Like Missy Elliot, we like to ["put our [Feather] down, flip it and reverse it"](https://www.youtube.com/watch?v=cjIvu7e6Wq8)&nbsp;and that's exactly what we've done with this new development board. It's basically our **<a...></a...>**

Out of Stock
[Buy Now](https://www.adafruit.com/product/5691)
[Related Guides to the Product](https://learn.adafruit.com/products/5691/guides)
### Adafruit Perma-Proto Half-sized Breadboard PCB - Single

[Adafruit Perma-Proto Half-sized Breadboard PCB - Single](https://www.adafruit.com/product/1609)
Customers have asked us to carry basic perf-board, but we never liked the look of most basic perf: it's always crummy quality, with pads that flake off and no labeling. Then we thought about how people **actually** prototype - usually starting with a solderless breadboard and...

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

[Piezo Buzzer](https://www.adafruit.com/product/160)
Piezo buzzers are used for making beeps, tones and alerts. This one is petite but loud! Drive it with 3-30V peak-to-peak square wave. To use, connect one pin to ground (either one) and the other pin to a square wave out from a timer or microcontroller. For the loudest tones, stay around 4 KHz,...

In Stock
[Buy Now](https://www.adafruit.com/product/160)
[Related Guides to the Product](https://learn.adafruit.com/products/160/guides)
### Adafruit PDM MEMS Microphone Breakout

[Adafruit PDM MEMS Microphone Breakout](https://www.adafruit.com/product/3492)
An exotic new microphone has arrived in the Adafruit shop, a **PDM MEMS Microphone**! PDM is the 'third' kind of microphone you can integrate with electronics, apart from analog or I2S. These microphones are very commonly used in products, but are rarely seen in maker...

In Stock
[Buy Now](https://www.adafruit.com/product/3492)
[Related Guides to the Product](https://learn.adafruit.com/products/3492/guides)
### NeoPixel Stick - 8 x 5050 RGB LED with Integrated Drivers

[NeoPixel Stick - 8 x 5050 RGB LED with Integrated Drivers](https://www.adafruit.com/product/1426)
Make your own little LED strip arrangement with this stick of NeoPixel LEDs. We crammed 8 of the tiny 5050 (5mm x 5mm) smart RGB LEDs onto a PCB with mounting holes and a chainable design. Use only one microcontroller pin to control as many as you can chain together! Each LED is addressable as...

In Stock
[Buy Now](https://www.adafruit.com/product/1426)
[Related Guides to the Product](https://learn.adafruit.com/products/1426/guides)
### Adafruit BME280 I2C or SPI Temperature Humidity Pressure Sensor

[Adafruit BME280 I2C or SPI Temperature Humidity Pressure Sensor](https://www.adafruit.com/product/2652)
Bosch has stepped up their game with their new BME280 sensor, an environmental sensor with temperature, barometric pressure&nbsp;and&nbsp;humidity! This sensor is great for all sorts of indoor environmental sensing and can even be used in both I2C and SPI!

This precision sensor from...

In Stock
[Buy Now](https://www.adafruit.com/product/2652)
[Related Guides to the Product](https://learn.adafruit.com/products/2652/guides)
### Adafruit VEML7700 Lux Sensor - I2C Light Sensor

[Adafruit VEML7700 Lux Sensor - I2C Light Sensor](https://www.adafruit.com/product/4162)
Vishay has a lot of light sensors out there, and this is a nice simple lux sensor that's easy to add to any microcontroller. Most light sensors just give you a number for brighter/darker ambient lighting. The VEML7700 makes your life easier by calculating the lux, which is an SI unit for...

In Stock
[Buy Now](https://www.adafruit.com/product/4162)
[Related Guides to the Product](https://learn.adafruit.com/products/4162/guides)
### Adafruit DRV2605L Haptic Motor Controller - STEMMA QT / Qwiic

[Adafruit DRV2605L Haptic Motor Controller - STEMMA QT / Qwiic](https://www.adafruit.com/product/2305)
The DRV2605 from TI is a fancy little motor driver. Rather than controlling a stepper motor or DC motor, its designed specifically for controlling **haptic** motors - buzzers and vibration motors. Normally one would just turn those kinds of motors on and off, but this driver has...

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

## Related Guides

- [Adafruit VEML7700 Ambient Light Sensor](https://learn.adafruit.com/adafruit-veml7700.md)
- [Adafruit ESP32-S3 Reverse TFT Feather](https://learn.adafruit.com/esp32-s3-reverse-tft-feather.md)
- [Star Trek Data Dispenser](https://learn.adafruit.com/star-trek-data-dispenser.md)
- [Convert your Model M Keyboard to Bluetooth with Bluefruit EZ-Key HID](https://learn.adafruit.com/convert-your-model-m-keyboard-to-bluetooth-with-bluefruit-ez-key-hid.md)
- [DIY Trinkey No-Soldering USB Air Quality Monitor](https://learn.adafruit.com/diy-trinkey-no-solder-air-quality-monitor.md)
- [No-Code Indoor Air Quality Monitor with Separate Display](https://learn.adafruit.com/no-code-indoor-air-quality-monitor-with-separate-display.md)
- [Adafruit IO Time Tracking Cube](https://learn.adafruit.com/time-tracking-cube.md)
- [PermaProto Feather Case](https://learn.adafruit.com/permaproto-feather-case.md)
- [Proximity Based Lighting](https://learn.adafruit.com/proximity-based-lighting.md)
- [Capacitive Touch Drum Machine](https://learn.adafruit.com/capacitive-touch-drum-machine.md)
- [CircuitPython Libraries on MicroPython using the Raspberry Pi Pico](https://learn.adafruit.com/circuitpython-libraries-on-micropython-using-the-raspberry-pi-pico.md)
- [IoT Air Quality Sensor with Adafruit IO](https://learn.adafruit.com/diy-air-quality-monitor.md)
- [RGB LED Matrix Cube with 25,000 LEDs](https://learn.adafruit.com/rgb-led-matrix-cube-for-pi.md)
- [Prop-Maker Feather Talking Adabot Clock](https://learn.adafruit.com/prop-maker-feather-talking-adabot-clock.md)
- [Integrating Home Assistant with Adafruit IO](https://learn.adafruit.com/integrating-adafruit-io-with-home-assistant.md)
- [Adafruit NeoPixel Überguide](https://learn.adafruit.com/adafruit-neopixel-uberguide.md)
- [MIDI Solenoid Drum Kit](https://learn.adafruit.com/midi-solenoid-drum-kit.md)
