# Star Trek Data Dispenser

## Overview

https://youtu.be/IYkjJc0lK-0

The TNG Data Dispenser is a wearable environmental monitor built into a 3D printed replica of the Drug Dispenser prop from "Encounter at Farpoint," the pilot episode of Star Trek: The Next Generation.

In the episode, the entity Q puts humanity on trial as a "dangerously savage child race." A soldier from Earth's Post-Atomic Horror era wears the device as an aerosol inhaler. "Rapid progress to where humans learned to control their military with drugs."

We thought - what if instead of dispensing drugs, it dispensed data? Real environmental data you can actually use.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/363/medium640/sensors_hero-engine.jpg?1774963678)

![](https://cdn-learn.adafruit.com/assets/assets/000/143/365/medium640/sensors_hero-shirt.jpg?1774963785)

This unit displays live CO2, humidity, temperature, and battery level as shaped colored bars that match the on-screen prop graphics. When CO2 levels get too high, a haptic motor buzzes to alert you.&nbsp;

Six display modes cycle through LCARS-style graphs, diagnostics, and a customizable name badge with a scannable QR code. It runs on a LiPo battery with automatic sleep and a brightness toggle for indoor use.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/364/medium640thumb/sensors_demo-loop.jpg?1774963729)

The Adafruit ESP32-S3 Reverse TFT Feather makes it easy to build display-first wearable projects. It has a built-in 240 x 135 color TFT and a STEMMA QT connector for plug-and-play I2C sensors. It features the ESP32-S3 with 4 megabytes of flash, 2 megabytes of PSRAM, WiFi, Bluetooth and an onboard MAX17048 battery fuel gauge that gives an accurate charge percentage and time remaining.

The STCC4 is a tiny CO2 sensor that can also read humidity, temperature and fits in just about any enclosure.&nbsp;

![](https://cdn-learn.adafruit.com/assets/assets/000/143/367/medium640/sensors_hero-board.jpg?1774964131)

We think this is a great project for cosplay, conventions and maker events where you want a prop that actually does something.

The LCARS graphs make it feel like a real piece of Starfleet equipment. The name badge screen shows your name, department, registry number, and a QR code that links to your project page.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/366/medium640/sensors_hero-qr.jpg?1774963868)

![](https://cdn-learn.adafruit.com/assets/assets/000/143/374/medium800/sensors_hero-ground.jpg?1774973487 )

![](https://cdn-learn.adafruit.com/assets/assets/000/143/375/medium800/sensors_parts.jpg?1774973508 )

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

In 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 STCC4 and SHT41 - CO2, Temperature & Humidity Sensor

[Adafruit STCC4 and SHT41 - CO2, Temperature & Humidity Sensor](https://www.adafruit.com/product/6478)
CO₂&nbsp;sensors are essential for determining if a room is too 'stuffy' - high CO₂ makes humans grumpy and tired. That's why it's always nice to take a deep breath outside where CO₂ is about 400 ppm. However, until now, CO₂ sensors were always really chunky (<a...></a...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/6478)
[Related Guides to the Product](https://learn.adafruit.com/products/6478/guides)
![Angled shot of CO2, temperature, and humidity sensor breakout.](https://cdn-shop.adafruit.com/640x480/6478-02.jpg)

### Lithium Ion Polymer Battery with Short Cable - 3.7V 420mAh

[Lithium Ion Polymer Battery with Short Cable - 3.7V 420mAh](https://www.adafruit.com/product/4236)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of 420mAh for a total of about 1.55 Wh. If you need a larger (or smaller!) battery, <a...></a...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/4236)
[Related Guides to the Product](https://learn.adafruit.com/products/4236/guides)
![Lithium Ion Polymer Battery 3.7v 420mAh with JST 2-PH connector and short cable](https://cdn-shop.adafruit.com/640x480/4236-04.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...>

Out of 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)

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

### Vibrating Mini Motor Disc

[Vibrating Mini Motor Disc](https://www.adafruit.com/product/1201)
\*BZZZZZZZZZZ\* Feel that? That's your little buzzing motor, and for any haptic feedback project you'll want to pick up a few of them. These vibe motors are tiny discs, completely sealed up so they're easy to use and embed.  
  
Two wires are used to control/power the vibe....

Out of Stock
[Buy Now](https://www.adafruit.com/product/1201)
[Related Guides to the Product](https://learn.adafruit.com/products/1201/guides)
![Vibrating Mini Motor Disc with two wires](https://cdn-shop.adafruit.com/640x480/1201-01.jpg)

### Magnetic Pin Back

[Magnetic Pin Back](https://www.adafruit.com/product/1170)
These magnetic pin backs have two pieces: a metal bar with adhesive strip and a plastic piece with two strong rare-earth magnets. Affix the metal bar to your FLORA projects-- it's just the right size! Then attach your FLORA project to any garment without poking holes in your clothes. The...

In Stock
[Buy Now](https://www.adafruit.com/product/1170)
[Related Guides to the Product](https://learn.adafruit.com/products/1170/guides)
![a metal bar with adhesive strip and a plastic piece.](https://cdn-shop.adafruit.com/640x480/1170-04.jpg)

### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

In Stock
[Buy Now](https://www.adafruit.com/product/4474)
[Related Guides to the Product](https://learn.adafruit.com/products/4474/guides)
![Angled shot of a coiled black, USB-C to USB-A cable.](https://cdn-shop.adafruit.com/640x480/4474-02.jpg)

### Part: M2.5X6mm Screws
quantity: 4
2 for the Feather 2 for the Magnet holder

### Part: M2X6mm Screws
quantity: 2
Feather mounts near the Reset button

### Part: M2X10mm Screws
quantity: 4
STEMMA holder

![](https://cdn-learn.adafruit.com/assets/assets/000/143/449/medium800/sensors_hero-wear.jpg?1775487940 )

# Star Trek Data Dispenser

## Circuit Diagram

This provides a visual reference for wiring of the components. This diagram was created using [Fritzing software](http://fritzing.org/download/).

![](https://cdn-learn.adafruit.com/assets/assets/000/143/388/medium800/sensors_fritz.jpg?1774982435 )

# Star Trek Data Dispenser

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

# Star Trek Data Dispenser

## Code

# Code the Data Dispenser

The&nbsp; **code.py** file runs the entire Data Dispenser - display graphics, sensor reads, button interactions, LCARS screens and sleep management. This page walks through each major section so you can customize the project or learn from the techniques used.

Click on the Download Project Bundle to get all the files for this project. Save the zip file where you can find it. Plug your Feather via USB into your computer via a known good USB data+power. A folder called **CIRCUITPY** should show up in Finder or File Explorer (depending on your operating system). Open the zip file and copy the files to the **CIRCUITPY** drive.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/380/medium640/sensors_cp-code-wide.jpg?1774980939)

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

### Required Libraries

Copy the&nbsp; **lib** &nbsp;folder from the zip file to your&nbsp; **CIRCUITPY** &nbsp;drive.&nbsp;

- **/adafruit\_display\_text**
- **adafruit\_stcc4.mpy**
- **adafruit\_max1704x.mpy**
- **/adafruit\_bus\_device**
- **/adafruit\_register**
- **adafruit\_drv2605.mpy**
- **adafruit\_miniqr.mpy**

When all the files are copied to **CIRCUITPY** , it should look like the file listing below. If you're missing any files, look in the zip file and copy them to the appropriate place.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/379/medium800/sensors_cp-drive.jpg?1774980865 )

The first block of constants at the top of&nbsp; **code.py** controls the sensor ranges, timing, and display behavior. These are the values you are most likely to want to edit.

```python
CO2_MIN = 400
CO2_MAX = 2000
CO2_WARN = 700
CO2_FLOOR_PCT = 8
TEMP_MIN = 15.0
TEMP_MAX = 40.0
UPDATE_INTERVAL = 2
HAPTIC_COOLDOWN = 30
LONG_PRESS_MS = 2000
IDLE_SLEEP_S = 300
DIM_BRIGHTNESS = 0.15
FULL_BRIGHTNESS = 1.0
```

- `CO2_WARN`&nbsp;— the CO2 level in ppm that triggers the haptic alert. Office air is typically 400 to 600 ppm.
- `CO2_FLOOR_PCT`&nbsp;— minimum visible bar height as a percentage so the CO2 bar is never completely empty.
- `TEMP_MIN`&nbsp;and&nbsp;`TEMP_MAX`&nbsp;— the temperature range in Celsius that maps to 0 to 100 percent on the bar.
- `UPDATE_INTERVAL`&nbsp;— seconds between sensor reads and display updates.
- `HAPTIC_COOLDOWN`&nbsp;— minimum seconds between haptic alerts to avoid constant buzzing.
- `LONG_PRESS_MS`&nbsp;— milliseconds a button must be held to trigger a long press action.
- `IDLE_SLEEP_S`&nbsp;— seconds of no button activity before the device automatically sleeps.
- `DIM_BRIGHTNESS`&nbsp;— display brightness when dimmed via D2 long press. Range is 0.0 to 1.0.

### Name Badge

The badge text is editable right below the tunables. These strings appear on the LCARS name badge screen and the QR code links to the URL you provide.

```python
BADGE_NAME = "P. RUIZ"
BADGE_TITLE = "ENGINEERING"
BADGE_ID = "NCC-1701-D"
BADGE_PROJECT = "TNG DATA DISPENSER"
BADGE_QR_URL = "https://learn.adafruit.com/u/pixil3d"
```

- `BADGE_NAME`&nbsp;— your name, displayed at 2x scale on the badge screen.
- `BADGE_TITLE`&nbsp;— department or role, shown in LCARS blue.
- `BADGE_ID`&nbsp;— registry number or ID, shown in LCARS orange.
- `BADGE_PROJECT`&nbsp;— project title shown at the bottom of the badge.
- `BADGE_QR_URL`&nbsp;— the URL encoded into the QR code. Use a short URL for a smaller, more scannable code. Set to an empty string to hide the QR code entirely.

### Colors and Anti-Aliasing

Each bar has a unique color — blue for CO2, green for humidity, yellow for temperature, red for battery. The code generates several dimmed variants of each color for the anti-aliasing layers.

```python
COLOR_CO2 = 0x4466FF
COLOR_HUMIDITY = 0x44FF66
COLOR_TEMP = 0xFFCC00
COLOR_BATTERY = 0xFF4444
```

The&nbsp;`dim_color()`&nbsp;function divides each RGB channel by a factor to produce darker versions. These are used for the five-layer polygon stack that makes each bar look smooth on the small 240 by 135 display. From bottom to top the layers are: outline glow at 10 percent brightness, colored track at 20 percent, full color fill, soft transition mask at 25 percent and dark mask for the unfilled portion.

### Bar Shape Geometry

The bar shape is an 8-point polygon that matches the tapered design from the original prop — narrow peak at the top, an asymmetric taper, and a wide base at the bottom. These coordinates were traced from an SVG of the prop's screen graphic.

```python
PEAK_L = 11
PEAK_R = 13
TAPER_L = 2
TAPER_R = 19
SHELF_L_Y = 57
SHELF_R_Y = 56
```

The&nbsp;`bar_shape()`&nbsp;function returns the outline,&nbsp;`mask_shape(pct)`&nbsp;computes the unfilled region for a given percentage, and&nbsp;`soft_mask_shape(pct)`&nbsp;adds a 1-pixel transition zone between the fill and the mask. This creates a subtle anti-alias effect at the fill line that softens the hard edge.

### Sensor Setup

All libraries are imported at the top of the file and sensors are initialized directly. The STEMMA QT I2C bus is created with a single call to&nbsp;`board.STEMMA_I2C()`. Each sensor is initialized without try/except wrapping — if a sensor is not found on the bus, the library raises an error that tells you to check your wiring.

```python
i2c = board.STEMMA_I2C()

sensor = adafruit_stcc4.STCC4(i2c)
sensor.continuous_measurement = True

batt = adafruit_max1704x.MAX17048(i2c)

haptic = adafruit_drv2605.DRV2605(i2c)
drv_effect = adafruit_drv2605.Effect
```

The STCC4 provides CO2, temperature and humidity. The MAX17048 provides battery percentage, voltage and charge rate. The DRV2605 drives the haptic motor for CO2 warning alerts and scan animation feedback.

### Charging Indicator and Battery Time

The MAX17048 fuel gauge provides&nbsp;`charge_rate`&nbsp;in percent per hour — positive when charging, negative when discharging. The code uses this to estimate time remaining.

```python
if is_charging:
    hrs = (100.0 - bat_r) / bat_rate
elif is_discharging:
    hrs = bat_r / abs(bat_rate)
```

When charging, a white lightning bolt and time-to-full appear inside the wide base of the battery bar. When discharging, the time remaining appears centered in the base without the bolt. The percentage label always stays in its normal position below the bar. Time shows as hours with one decimal, or switches to minutes when under one hour.

### Scan Animations

There are three animation styles. The boot scan sweeps all four bars from zero to 100 percent with a staggered cascade, then settles each bar to its sensor reading. The rescan animation starts from the current fill level, surges to 100 percent, drains to zero and then fills to the new reading. The solo scan does the same sequence on a single bar for the Fahrenheit to Celsius toggle.

```python
def rescan_animation(current, targets):
    # Phase 1: fill from current to 100%
    # Phase 2: drain 100% to 0%
    # Phase 3: fill 0% to targets with stagger
```

All animations use&nbsp;`SCAN_STEPS`&nbsp;of 20 frames at&nbsp;`SCAN_DELAY`&nbsp;of 30 milliseconds each, with a&nbsp;`SCAN_STAGGER`&nbsp;of 3 frames between bars. A three-pulse haptic buzz plays at the start of every scan.

### LCARS Graph System

Three LCARS-style bar histogram screens show two hours of CO2, humidity and temperature history. All three use the same pair of functions:&nbsp;`create_sensor_graph(view_mode)`&nbsp;builds the display group and&nbsp;`update_sensor_graph(view_mode)`&nbsp;redraws the bitmap. Each graph is stored in the&nbsp;`sensor_graphs`&nbsp;dictionary and built lazily on first access.

```python
def create_sensor_graph(view_mode):
    if view_mode == VIEW_CO2:
        grp, bmp, vlbl, mlbl = _build_lcars_graph(
            "CO2", "PPM",
            GRAPH_CO2_LO, GRAPH_CO2_HI,
            LCARS_GOLD, CO2_ZONES,
        )
    ...
    sensor_graphs[view_mode] = (grp, bmp, vlbl, mlbl)
```

The&nbsp;`graph_layout()`&nbsp;function dynamically sizes the bars based on how much data exists. With only a few samples the bars are wide and chunky, filling half the graph width. As data accumulates over two hours the bars slim down and the graph expands to fill the full width.

Each bar is colored by the reading's value — green for safe levels, yellow for elevated and red for high. A 1-pixel gap separates each bar. Each sensor type has its own zone thresholds defined as a list of tuples.

- `GRAPH_CO2_LO`&nbsp;and&nbsp;`GRAPH_CO2_HI`&nbsp;— the floor and ceiling for the CO2 graph. The floor is set to 300 so that normal 400 ppm readings have visible bar height.
- `HISTORY_SIZE`&nbsp;— number of samples stored. At 120 samples with a 60-second interval this gives 2 hours of data.
- `SAMPLE_INTERVAL`&nbsp;— seconds between history samples. All three sensors are sampled together.
- `ZOOM_SAMPLES`&nbsp;— number of samples shown when zoomed in. Set to 15 for a 15-minute window.

### LCARS Stats Screen

The diagnostics screen shows session data in a two-column layout with LCARS blue labels on the left and gold values on the right. It displays uptime in hours and minutes, samples collected out of 120, and current reading with min/max range for CO2, humidity and temperature. The battery percentage is shown at the bottom. Temperature min/max respects the current Fahrenheit or Celsius setting.

### LCARS Name Badge

The badge uses a gold LCARS frame with blue, orange, and red accent blocks across the top. Your name renders at 2x scale for visibility. Below that are the title, ID and project name. The QR code is generated at runtime using the&nbsp;`adafruit_miniqr`&nbsp;library and positioned on the right side of the screen. It uses low error correction and type-3 encoding to keep the module count small enough to scan from the 135-pixel display.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/452/medium800/sensors_buttons.jpg?1775491400 )

### View Cycling

Six views are available. D2 short press cycles through the first five in order: bars, stats, CO2 graph, humidity graph, temperature graph. The about/badge screen is accessed separately via D1 long press. D0 short press always returns to the bar view from any other screen.

```python
VIEW_BARS = 0
VIEW_STATS = 1
VIEW_CO2 = 2
VIEW_HUM = 3
VIEW_TEMP = 4
VIEW_ABOUT = 5
```

Each LCARS screen is built lazily the first time it is accessed using the&nbsp;`sensor_graphs`&nbsp;dictionary. The graph zoom state resets when cycling away from graph views.

### Button System

The button polling runs inside the sensor update interval at 50-millisecond resolution. Each button tracks its press-down timestamp for long press detection and a flag to prevent the short press from firing after a long press.

D0 also supports double-tap detection. On release, the short press action is delayed by&nbsp;`DOUBLE_TAP_MS`&nbsp;of 400 milliseconds. If D0 is pressed again within that window, it triggers demo mode instead. The D0 plus D2 combo hold is checked inside the D0 long press handler — if D2 is also held when D0 reaches the long press threshold, it triggers sleep.

```python
Button map:
  D0 short:  rescan / return to bars
  D0 double: demo mode
  D0 long:   CO2 calibration
  D1 short:  F/C toggle (bars) / zoom (graphs)
  D1 long:   toggle name badge
  D2 short:  cycle views
  D2 long:   brightness toggle
  D0+D2:     sleep
```

### Sleep Mode

The project uses light sleep instead of deep sleep because the ESP32-S3 Reverse TFT Feather's D0/BOOT0 pin has external circuitry that causes false wake triggers with PinAlarm. The light sleep approach blanks the display and enters a loop that sleeps for 2 seconds at a time using TimeAlarm, then polls the buttons.

```python
while True:
    t_alarm = alarm.time.TimeAlarm(
        monotonic_time=time.monotonic() + 2
    )
    alarm.light_sleep_until_alarms(t_alarm)
    if not btn_d0.value or btn_d1.value or btn_d2.value:
        break
```

Before sleeping, the code waits for all buttons to be released to prevent immediate wake. The CO2 calibration offset is saved to&nbsp;`alarm.sleep_memory`&nbsp;so it persists. On wake, the display brightness is restored and a boot scan animation plays. Sleep triggers automatically after 5 minutes of no button activity or manually with a D0 plus D2 long press.

### CO2 Calibration

Long pressing D0 runs a software CO2 offset calibration. Take the device outside to fresh air and hold D0 for 2 seconds. The code reads the current CO2 value and computes the offset needed to map it to 400 ppm, the standard outdoor baseline.

```python
co2_offset = 400 - int(raw)
save_co2_offset()
```

The offset is stored as a 4-byte signed integer in&nbsp;`alarm.sleep_memory`&nbsp;bytes 0 through 3, written byte-by-byte since the ESP32-S3 port does not support&nbsp;`struct.pack_into`&nbsp;directly on the sleep memory object. The offset applies to all readings going forward and survives sleep/wake cycles. To clear it, calibrate again in known-good air.

### Demo Mode

Double-tapping D0 activates demo mode for hands-free video recording. It cycles through every screen automatically with a 3-second hold on each.

1. Bar view with rescan animation
2. LCARS diagnostics
3. CO2 graph zoomed in (15 minutes)
4. CO2 graph full view
5. Humidity graph zoomed in
6. Humidity graph full view
7. Temperature graph zoomed in
8. Temperature graph full view
9. LCARS name badge with QR code
10. Return to bars with scan animation

- `DEMO_HOLD`&nbsp;— seconds to hold on each screen. Default is 3.

# Star Trek Data Dispenser

## 3D Printing

3MF files for 3D printing are oriented and ready to print on FDM machines using PLA filament. Original design source files may be downloaded using the links below.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/382/medium640/sensors_parts-3d.jpg?1774981057)

[Edit Design](https://a360.co/4tnM0kT)
[Star Trek Data Dispenser.3mf](https://cdn-learn.adafruit.com/assets/assets/000/143/383/original/Star-Trek-Data-Dispenser.3mf?1774981271)
Info: The dropdown on the Fusion 360 site allows you to pick your preferred 3D file format like STEP, STL, etc.

### Slice with settings for PLA material

The parts were sliced using BambuStudio using the slice settings below.

- PLA filament 220c extruder
- 0.2 layer height
- 10% gyroid infill
- 200mm/s print speed
- Tree Supports
- 60 C heated bed

![](https://cdn-learn.adafruit.com/assets/assets/000/143/381/medium640/sensors_slice.jpg?1774980993)

## Grid Setting for Sensor

The sensor portion of the case uses separate settings to generate a grid infill with no tops or bottoms.

- Infill density: 60%
- Sparse infill pattern: Grid
- Top + Bottom shell: 0
- Top + Bottom penetration layers: 0

![](https://cdn-learn.adafruit.com/assets/assets/000/143/386/medium640/sensors_slice-grid.jpg?1774981876)

## Design Source Files

The project assembly was designed in Fusion 360. Once opened in Fusion 360, It can be exported in different formats like STEP, STL and more.

Electronic components like Adafruit's boards, displays, connectors and more can be downloaded from the&nbsp;[Adafruit CAD parts GitHub Repo](https://github.com/adafruit/Adafruit_CAD_Parts/)

![](https://cdn-learn.adafruit.com/assets/assets/000/143/387/medium640/sensors_cad.jpg?1774982341)

# Star Trek Data Dispenser

## Assembly

## Solder Motor

Solder the **Red** wire to the **+** pad and the **Blue** to the **-** pad on the DRV board.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/349/medium640/sensors_motor-solder.jpg?1774921780)

## STEMMA QT Chain of Devices

Connect a 50mm long STEMMA QT cable to the port on the Feather.&nbsp;

The STCC4 / SHT41 - CO2 board connects next in the STEMMA QT chain, followed by the DRV board at the end.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/350/medium640/sensors_setmma-chained.jpg?1774922026)

## STEMMA QT Sandwich&nbsp;

Place the board standoff between the DVR board below and the STCC4 board on top. Use the extruded standoff portion to clear the STEMMA QT ports on the DVR board.

Use M2.5x10mm screws to&nbsp;securely mount the STEMMA QT sandwich together.&nbsp;

![](https://cdn-learn.adafruit.com/assets/assets/000/143/351/medium640/sensors_stemma-sandwich.jpg?1774922387)

## Mount Motor

Align the wires on the vibration motor to the cutaway on the circular wall in the case.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/352/medium640/sensors_motor-mount.jpg?1774922815)

## Mount Boards

Secure the Feather to the stand-offs on the case with two M2.5x6mm screws on the side closest to the three buttons. Use two M2x6mm screws on the remaining screw mounts closest to the Reset button.&nbsp;

Position the STEMMA QT sandwich to the stand-offs inside the case.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/353/medium640/sensors_board-mount.jpg?1774923307)

## Connect Lipo Battery

Align the battery cable to the JST port on the Feather.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/354/medium640/sensors_board-mounted.jpg?1774923904)

## Weathering Paint

Use dark grey acrylic paint to add weathering details to the front and side of the case.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/355/medium640/sensors_weathering.jpg?1774924263)

![](https://cdn-learn.adafruit.com/assets/assets/000/143/446/medium640/sensors_weathering-paint.jpg?1775414263)

## Snap-fit Case Top

Align the snap fit nubs to connect the top of the case to the bottom of the case.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/356/medium640/sensors_snap-aligned.jpg?1774924425)

![](https://cdn-learn.adafruit.com/assets/assets/000/143/358/medium640/sensors_snap.jpg?1774924791)

![](https://cdn-learn.adafruit.com/assets/assets/000/143/359/medium800/sensors_snapped.jpg?1774924832 )

## Assemble Magnetic Backing

The magnetic pin backing attaches to the case with a printed holder.

Align the magnets through the cutouts on the holder.

Use two M2.5x6mm screws to attach the holder to the back of the case.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/360/medium640/sensors_magnetic-align.jpg?1774924879)

![](https://cdn-learn.adafruit.com/assets/assets/000/143/361/medium640/sensors_magnetic-mounted.jpg?1774925070)

![](https://cdn-learn.adafruit.com/assets/assets/000/143/362/medium800/sensors_hero-shirt.jpg?1774925148 )

# Star Trek Data Dispenser

## Usage

The Data Dispenser has three buttons along the edge of the Feather board, labeled D0, D1, and D2 from top to bottom. Each button has a short press, long press and in some cases a double-tap or combo action. This page covers every feature and how to access it.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/423/medium800thumb/sensors_demo-loop.jpg?1775246690 )

### Quick Reference

```
D0 short Rescan animation / return to bars
D0 double Demo mode (auto-cycle all screens)
D0 long CO2 offset calibration
D1 short F/C toggle (bars) / zoom (graphs)
D1 long Toggle LCARS name badge
D2 short Cycle views
D2 long Toggle brightness (full / dim)
D0+D2 long Sleep
5 min idle Auto sleep
Any button Wake from sleep
```
![](https://cdn-learn.adafruit.com/assets/assets/000/143/454/medium800/temperature___humidity_buttons.jpg?1775491634 )

### Boot Up

When you power on the device or wake it from sleep, the display runs a scan animation. All four bars sweep up from zero to full, then settle to the current sensor readings. A three-pulse haptic buzz confirms the scan. The STCC4 sensor needs a couple of seconds to stabilize after power-on, so the first CO2 reading may be slightly off — it settles within a few update cycles.

### Bar Graph View

This is the default home screen. Four shaped colored bars show live sensor data, each updating every two seconds. From left to right the bars are:

- Blue for CO2 in parts per million
- Green for humidity as a percentage
- Yellow for temperature in Fahrenheit or Celsius
- Red for battery level as a percentage.

The bar shape matches the original prop's on-screen graphic — a narrow peak at the top that tapers into a wide base. Each bar has a subtle anti-aliased edge and a colored gradient background behind it.

The label below each bar shows the current value. CO2 displays as a raw ppm number, humidity and battery show a percentage, and temperature shows the value either in Fahrenheit (F) or Celsius (C).

![](https://cdn-learn.adafruit.com/assets/assets/000/143/466/medium800/temperature___humidity_screen-charge.jpg?1775598201 )

### Battery Indicator

When the device is charging via USB, a blinking white lightning bolt appears inside the base of the battery bar along with the estimated time to full charge. The percentage label stays in its normal position below the bar.

When running on battery, the estimated time remaining appears inside the bar base in white text. The estimate becomes more accurate after a few minutes as the MAX17048 fuel gauge learns the current draw. Under one hour it switches from hours to minutes.

### CO2 Warning Alert

When the CO2 reading exceeds the warning threshold of 700 ppm, the haptic motor fires a double-pulse vibration alert. The alert has a 30-second cooldown to avoid constant buzzing in a stuffy room. You can adjust the threshold by changing&nbsp;`CO2_WARN`&nbsp;in the tunables section of&nbsp; **code.py**.

### &nbsp;
![](https://cdn-learn.adafruit.com/assets/assets/000/143/469/medium800/temperature___humidity_screen-sleep.jpg?1775598492 )

### Sleep Mode

**D0 plus D2 long press:** &nbsp;Hold both D0 and D2 for two seconds to put the device to sleep immediately. The display blanks and the device enters a low-power light sleep loop.

**Auto sleep:** &nbsp;If no button is pressed for five minutes, the device sleeps automatically. You can change this timeout by editing&nbsp;`IDLE_SLEEP_S`&nbsp;in the tunables.

**Wake:** &nbsp;Press any button to wake the device. The display restores to the previous brightness setting and a boot scan animation plays. The CO2 calibration offset is preserved across sleep.

&nbsp;

![](https://cdn-learn.adafruit.com/assets/assets/000/143/467/medium800/temperature___humidity_screen-calibrate.jpg?1775598292 )

### Button D0 — Scan and Calibrate

**Short press:** &nbsp;On the bar view, D0 triggers a rescan animation. The bars surge from their current level to full, drain to empty, then refill to the latest sensor values with a staggered cascade. On any other screen, D0 returns you to the bar view.

**Double tap:** &nbsp;Quickly press D0 twice to enter demo mode. The device automatically cycles through every screen with a three-second hold on each — bar view with animation, diagnostics, all three graphs in both zoomed and full views, the name badge, then back to bars. This is hands-free and great for video recording or showing off the prop.

**Long press (2 seconds):**&nbsp;Runs CO2 offset calibration. Take the device outside to fresh air first. Hold D0 for two seconds and the screen shows CALIBRATING followed by the computed offset value. The offset adjusts all future CO2 readings so that outdoor air reads as 400 ppm. The offset is saved to sleep memory and survives sleep/wake cycles. To reset the calibration, repeat the process in known-good outdoor air.

&nbsp;

![](https://cdn-learn.adafruit.com/assets/assets/000/143/470/medium800/temperature___humidity_screen-graphs.jpg?1775598551 )

### Button D1 — Toggle and Zoom

**Short press on bar view:** &nbsp;Toggles the temperature display between Fahrenheit and Celsius. The temperature bar plays a solo rescan animation — surging to full, draining, then refilling with the new unit label.

**Short press on graph views:** &nbsp;Toggles zoom. When zoomed in, the graph shows the last 15 minutes of data with wide chunky bars that fill the full graph width. Press again to zoom back out to the full history view. The zoom state resets when you leave the graph views.

**Long press (2 seconds):**&nbsp;Toggles the LCARS name badge screen. Long press again to return to whatever view you were on before.

### Button D2 — Cycle Views and Brightness

**Short press:** &nbsp;Cycles through the display views in order: bar graph, LCARS diagnostics, CO2 graph, humidity graph, temperature graph, then back to bars. Each graph screen is built the first time you access it to save memory at boot.

**Long press (2 seconds):**&nbsp;Toggles display brightness between full (1.0) and dim (0.15). The dim mode is useful for indoor display or when the bright screen would be distracting. The brightness setting is remembered through sleep/wake cycles.

&nbsp;

![](https://cdn-learn.adafruit.com/assets/assets/000/143/471/medium800/temperature___humidity_screen-dia.jpg?1775598677 )

### LCARS Diagnostics Screen

The stats screen shows a two-column layout with LCARS-style framing. The left column has labels in blue and values in gold on the right. It displays the current session uptime in hours and minutes, the number of history samples collected out of 120, and the current reading with session min/max range for CO2, humidity and temperature. Battery percentage is shown at the bottom.

### LCARS Graph Screens

Three separate graph screens show rolling history for CO2, humidity and temperature. Each graph is a bar histogram with the LCARS frame on the left showing the current value, unit, min/max range and a 2HR time window label.

The bars are color-coded by zone. For CO2, green is safe (under 600 ppm), yellow is elevated (600 to 800 ppm) and red is high (above 800 ppm). Humidity and temperature have their own zone thresholds tuned to typical comfort ranges.

Data is sampled every 60 seconds into a circular buffer of 120 entries, giving two hours of rolling history. The bar width adjusts dynamically — with just a few samples the bars are wide and centered, gradually slimming down as the buffer fills. Dashed threshold lines mark the zone boundaries.

Press D1 on any graph screen to toggle zoom. The zoomed view shows the last 15 minutes with wide bars for a detailed close-up of recent changes.

&nbsp;

![](https://cdn-learn.adafruit.com/assets/assets/000/143/468/medium800/temperature___humidity_screen-qr.jpg?1775598325 )

### LCARS Name Badge

The badge screen shows your personalized information in the LCARS style with a gold frame and colored accent blocks. Your name appears at double size, followed by your title, registry ID, sensor status and project name. A QR code on the right side links to the URL you specify — scannable directly from the display at conventions or meetups.

All badge text is editable in the tunables section at the top of&nbsp; **code.py** :&nbsp;`BADGE_NAME`,&nbsp;`BADGE_TITLE`,&nbsp;`BADGE_ID`,&nbsp;`BADGE_PROJECT`&nbsp;and&nbsp;`BADGE_QR_URL`. Set the QR URL to an empty string to hide the QR code.

![](https://cdn-learn.adafruit.com/assets/assets/000/143/450/medium800/sensors_hero-console.jpg?1775487990 )


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

In Stock
[Buy Now](https://www.adafruit.com/product/5691)
[Related Guides to the Product](https://learn.adafruit.com/products/5691/guides)
### Adafruit STCC4 and SHT41 - CO2, Temperature & Humidity Sensor

[Adafruit STCC4 and SHT41 - CO2, Temperature & Humidity Sensor](https://www.adafruit.com/product/6478)
CO₂&nbsp;sensors are essential for determining if a room is too 'stuffy' - high CO₂ makes humans grumpy and tired. That's why it's always nice to take a deep breath outside where CO₂ is about 400 ppm. However, until now, CO₂ sensors were always really chunky (<a...></a...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/6478)
[Related Guides to the Product](https://learn.adafruit.com/products/6478/guides)
### Lithium Ion Polymer Battery with Short Cable - 3.7V 420mAh

[Lithium Ion Polymer Battery with Short Cable - 3.7V 420mAh](https://www.adafruit.com/product/4236)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of 420mAh for a total of about 1.55 Wh. If you need a larger (or smaller!) battery, <a...></a...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/4236)
[Related Guides to the Product](https://learn.adafruit.com/products/4236/guides)
### 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...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/4399)
[Related Guides to the Product](https://learn.adafruit.com/products/4399/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)
### Vibrating Mini Motor Disc

[Vibrating Mini Motor Disc](https://www.adafruit.com/product/1201)
\*BZZZZZZZZZZ\* Feel that? That's your little buzzing motor, and for any haptic feedback project you'll want to pick up a few of them. These vibe motors are tiny discs, completely sealed up so they're easy to use and embed.  
  
Two wires are used to control/power the vibe....

Out of Stock
[Buy Now](https://www.adafruit.com/product/1201)
[Related Guides to the Product](https://learn.adafruit.com/products/1201/guides)
### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

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

[Magnetic Pin Back](https://www.adafruit.com/product/1170)
These magnetic pin backs have two pieces: a metal bar with adhesive strip and a plastic piece with two strong rare-earth magnets. Affix the metal bar to your FLORA projects-- it's just the right size! Then attach your FLORA project to any garment without poking holes in your clothes. The...

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

## Related Guides

- [Adafruit ESP32-S3 Reverse TFT Feather](https://learn.adafruit.com/esp32-s3-reverse-tft-feather.md)
- [Adafruit STCC4 and SHT41 CO2, Temperature & Humidity Sensor](https://learn.adafruit.com/adafruit-stcc4-and-sht41-co2-temperature-humidity-sensor.md)
- [BLE Vibration Bracelet](https://learn.adafruit.com/ble-vibration-bracelet.md)
- [CircuitPython Elgato WiFi Light Controller](https://learn.adafruit.com/circuitpython-elgato-wifi-light-controller.md)
- [BLE Buzzy Box](https://learn.adafruit.com/ble-buzzy-box.md)
- [I2C Addresses and Troublesome Chips](https://learn.adafruit.com/i2c-addresses.md)
- [Haptic Headband](https://learn.adafruit.com/haptic-headband.md)
- [Severance Portable Macrodata Refinement Terminal](https://learn.adafruit.com/portable-macrodata-refinement-terminal.md)
- [ESP32-S2 Reverse TFT Digital Clock Display featuring Blanka-chan!](https://learn.adafruit.com/esp32-s2-tft-digital-clock-display-featuring-blanka-chan.md)
- [CircuitPython Day 2024 Countdown Clock](https://learn.adafruit.com/circuitpython-day-2024-countdown-clock.md)
- [ESP-NOW in CircuitPython](https://learn.adafruit.com/esp-now-in-circuitpython.md)
- [Cheekmate - a Wireless Haptic Communication System](https://learn.adafruit.com/cheekmate-wireless-haptic-communication.md)
- [Adafruit DRV2605L Haptic Controller Breakout](https://learn.adafruit.com/adafruit-drv2605-haptic-controller-breakout.md)
- [Use Apple HomeKit Devices with itsaSNAP and Adafruit IO](https://learn.adafruit.com/use-apple-homekit-devices-with-itsasnap.md)
- [1D Chomper Tabletop Arcade Game](https://learn.adafruit.com/1d-chomper-tabletop-arcade-game.md)
