Open the external LED starterLearn the supporting theoryReview the current calculationExplore temperature hysteresisRecord LED measurementsInspect sensor readings
← Back

This preview is the content that will print. Choose “Save as PDF” in your browser’s print dialog to make a PDF.

Metatransformer report

Buy and build — Pico + BME280 external LED indicator

Standalone procurement, wiring, firmware, measurement, and evidence handoff · researched but unbuilt

Text report: images and diagrams are omitted, and links to project files are inactive. Keep the exported project alongside this PDF for wiring diagrams, models, and linked files.

Build status and exact route

This is a researched, unbuilt learning bench. It has not been wired, flashed, measured, calibrated, or physically validated. Use only the original Raspberry Pi Pico RP2040 sold as Adafruit product 4883 and the Adafruit BME280 STEMMA QT breakout sold as product 2652. Do not silently substitute Pico W, Pico 2, BMP280, a bare sensor, or a different breakout.

USB is the only power source. The BME280 is powered from the Pico's 3V3(OUT), and one red 5 mm LED is driven from GP2 through a 1 kΩ series resistor. The LED is a commanded temperature indicator, not a sensor, alarm, calibrated display, or proof of the measured temperature. Physical brightness, sensor accuracy, actual GPIO voltage, and the received components' behavior remain unknown until observed and recorded.

Procurement and receiving inspection

“Acquire” counts packages; “used” counts parts that enter one build. Check existing supplies first. These links identify exact selections, not current price, stock, shipping, or a purchase recommendation.

Exact itemAcquire if absentUsed in one buildReceiving check
Original Raspberry Pi Pico RP2040 with loose headers, Adafruit product 4883 (opens in a new tab)1 board package1 Pico and its two included 20-pin stripsConfirm original Pico markings; reject an unintended W or Pico 2 variant.
Adafruit BME280 STEMMA QT breakout, product 2652 (opens in a new tab)1 breakout package1 breakout and fitted pad-row headerConfirm BME280 rather than BMP280; inspect the board and supplied loose header.
Full-size breadboard, Adafruit product 239 (opens in a new tab)11Confirm the center trench and the actual five-contact strip pattern.
Male/male jumper ribbon, Adafruit product 758 (opens in a new tab)1 pack6 conductors: 4 sensor, 1 GP2, 1 GNDBoth ends must be male; one pack is not one wire.
Clear red 5 mm LEDs, Adafruit product 297 (opens in a new tab)1 pack of 251 LEDKeep the received packaging or datasheet for identity and polarity checks.
1 kΩ ±5%, 1/4 W axial resistors, Adafruit product 4294 (opens in a new tab)1 pack of 251 resistorConfirm markings and measure the isolated part before fitting it.
USB-A to Micro-B data cable, product 592 (opens in a new tab)Choose 1 for a USB-A host1Must carry data and power.
USB-C to Micro-B data cable, product 3878 (opens in a new tab)Choose instead for a USB-C host1Replaces the USB-A option; Micro-B is not Mini-B.
0.1-inch 36-pin male header 10-pack, product 392 (opens in a new tab)0 normally; optionally 1 pack if the BME280 header is missing or damagedOne uninterrupted piece matching the received BME280 pad rowCount the actual pads before cutting; this is not a required substitute for the Pico's included headers.

Required bench tools are a continuity/resistance/DC-voltage multimeter, soldering iron and stand, electronics solder, eye protection, ventilation, and side cutters only if a replacement header must be sized. Work on a clear nonconductive surface. Header soldering and every resistance or continuity check happen with USB disconnected.

Identify the LED from the received part, not from its red color. Adafruit's LED guide (opens in a new tab) describes the flat package edge and shorter lead as cathode clues. Lead length is unreliable after trimming, so inspect the flat edge, verify those clues against the received LED's datasheet or packaging, and stop if polarity remains uncertain. Do not “test” an unknown LED by removing the resistor.

Headers, breadboard, and exact unpowered wiring

  1. Confirm the exact board identities, Pico header strips, BME280 pad count, LED identity, and 1 kΩ resistor before assembly. Measure the isolated, unpowered resistor and record its resistance; a nominal ±5% part should fall from 950 Ω to 1050 Ω. Stop on an unexplained result.
  2. Fit the Pico headers long-pins-down toward the breadboard, with short ends through the Pico. Keep both strips straight and solder every fitted pad. Fit one continuous BME280 header to its pad row in the same orientation and solder every populated pad. Loose pressed pins are not joints.
  3. After cooling, inspect both boards for bridges, missed joints, bent pins, and debris. Straddle the breadboard center trench with the Pico. Put every BME280 pin in a different connected strip. Inspect the actual breadboard pattern; do not assume a power rail or hidden split is continuous.
  4. Use the official numbered Pico pinout (opens in a new tab) and the BME280 labels. VIN is used; 3Vo remains disconnected. VBUS physical pin 40 remains disconnected. Wire the four sensor paths and the two LED jumpers exactly as shown.
ORIGINAL PICO                         ADAFRUIT BME280
physical 1  GP0  (SDA)  -----------> SDI / SDA
physical 2  GP1  (SCL)  -----------> SCK / SCL
physical 36 3V3(OUT)     -----------> VIN
physical 38 GND          -----------> GND

ORIGINAL PICO                         SERIES INDICATOR PATH
physical 4  GP2 --------> [ 1 kΩ ] -> LED anode (+)
                                           LED cathode (-) -> physical 3 GND

On the breadboard, use three electrically distinct contact strips for the LED branch: node A joins the GP2 jumper to one resistor lead; node B joins the other resistor lead to the LED anode; node C joins the LED cathode to the GND jumper. The two resistor leads must not share a strip, the two LED leads must not share a strip, and no conductor may bridge around the resistor. This describes electrical nodes, not an invented row or board placement.

Before USB, trace every path endpoint-to-endpoint and verify that adjacent intended nodes are not accidentally continuous. Confirm no short from 3V3(OUT) to GND and no connection to VBUS. Resolve any uncertain pin, polarity, strip, bridge, or measurement before power.

CircuitPython and source handoff

Install the official original-Pico CircuitPython UF2 (opens in a new tab): hold BOOTSEL while attaching the USB data cable, copy the correct UF2 to RPI-RP2, and wait for the restart to expose CIRCUITPY. Download the CircuitPython library bundle (opens in a new tab) whose major version matches the installed CircuitPython major version. Copy the complete adafruit_bme280, adafruit_bus_device, and adafruit_register directories into CIRCUITPY/lib.

Copy both source files to the CIRCUITPY root: copy firmware/code.py as code.py and firmware/indicator.py as indicator.py. Do not merge them or leave indicator.py inside a firmware directory on the device. The packet's source files own the behavior; do not retype fragments from the printed guide.

In Metatransformer choose New project → Pico + BME280 external LED indicator to obtain the source packet. Keep README.md, BUY_AND_BUILD.md, WIRING.md, ENGINEERING.md, firmware/behavior.md, both Python files, and both notes CSV files together. Use Export source after reviewing notes for private information. A recipient can import the bundle with pnpm workshop import /path/to/build.workshop.json /path/to/new-build, then register it with pnpm workshop register /path/to/new-build. Use a new destination directory. Recheck the received hardware and wiring after transfer; source portability is not physical validation.

Firmware contract

GP2 is configured as an active-high output with its first commanded value false. Before any sensor initialization, firmware commands exactly three startup pulses: 0.2 seconds on followed by 0.2 seconds off, repeated three times, then leaves the LED off. These pulses test only the commanded output path; they do not prove that light was emitted.

After initialization, temperature at or above 28 °C commands the LED on, temperature at or below 26 °C commands it off, and a finite temperature strictly between those thresholds retains the prior state. Once per second, a successful sample prints timestamp,temp_c,humidity_pct,pressure_hpa,led. The final field is the commanded GP2 state, not an optical measurement.

The scan accepts exactly one supported BME280 address, 0x76 or 0x77, unless ADDRESS explicitly selects a detected supported address. No supported address, both addresses without an explicit selection, initialization failure, read failure, or any non-finite temperature, humidity, or pressure value clears the LED off, clears hysteresis state, prints a comment-prefixed error, and retries after one second. Faults never blink the LED; the three boot pulses are intentionally unique. Recovery begins from an off state.

Staged acceptance and measurement

  1. Unpowered identity and path check: identify both boards, the LED polarity, and the resistor; measure the isolated resistor; inspect solder; trace all four sensor paths and the complete GP2–resistor–LED–GND path. Expected: the documented endpoints and no resistor bypass. Record facts, not expected values as observations.
  2. Startup indication: with intact wiring, connect USB and watch one boot. Expected command: three 0.2-second on/off pulses before sensor initialization, ending off. Imports run before the startup pulses: if no light is observed, first inspect the USB serial traceback for missing files or libraries. Do not bypass the resistor. Disconnect USB and inspect firmware placement, GP2/GND endpoints, breadboard nodes, LED identity and polarity, and joints.
  3. Sensor and CSV: open the serial console. Expected: a startup comment, one detected 0x76 or 0x77 address, one CSV header, and finite five-field rows roughly once per second. Record the address and actual rows. Plausible output is not calibration evidence.
  4. Controlled threshold check: read a stable ambient value T from CSV. Edit HIGH_C and LOW_C near the top of CIRCUITPY/code.py, not the defaults in indicator.py. For forced ON, use HIGH_C = T − 1 and LOW_C = T − 2; for forced OFF, use HIGH_C = T + 2 and LOW_C = T + 1. Substitute actual numbers: at T = 23, ON uses 22/21 and OFF uses 25/24. Save each configuration and wait through the three startup pulses for normal CSV, then record commanded and observed light. Saving restarts CircuitPython and resets state: these checks demonstrate ON/OFF, not retained-state memory. Retention requires crossing a threshold and returning into the gap during one uninterrupted run; if ordinary ambient changes cannot do this, record that bench check as pending (the pure Python tests cover the rule). Do not use hazardous heating. Restore HIGH_C = 28.0 and LOW_C = 26.0 in code.py afterward.
  5. Electrical observation: with the series circuit intact and LED commanded on, measure DC voltage across the resistor using a high-impedance voltage input. Infer current from measured I = V_R / R_measured; record voltage, measured resistance, and calculated current. Do not place an ammeter across GP2 and GND or across the LED—an ammeter is not a high-impedance voltage probe.
  6. Fault and recovery: disconnect USB before removing the BME280 wires. Reconnect USB with the sensor absent. Expected: the three startup pulses occur once, then the output stays off while comment-prefixed initialization errors retry about once per second; there is no fault blink. Disconnect USB again, restore all four sensor wires, inspect, and reboot. Expected: three startup pulses, sensor detection, and CSV rows resume without editing firmware.

Disconnect immediately for heat, odor, smoke, instability, a suspected power/ground crossing, or damaged insulation. Do not rewire or use resistance/continuity mode while powered.

Engineering calculation and learning check

The LED seller publishes a 1.8–2.2 V forward-voltage range at 20 mA. That range is not specified at this bench's roughly 1 mA operating point, so 2.0 V is an explicit modeling assumption rather than a measured fact. With an assumed 3.3 V output, 2.0 V LED drop, and 1000 Ω resistance:

I = (3.3 V - 2.0 V) / 1000 Ω = 0.0013 A = 1.3 mA
P_resistor = I²R = (0.0013 A)² × 1000 Ω = 0.00169 W = 1.69 mW

Learning check—before reading the next paragraph, answer: What is the nominal modeled LED current, and why does the forward-voltage assumption matter? Review Ohm's law and digital interfaces if helpful.

Answer: the nominal modeled current is 1.3 mA. The assumed LED drop determines how much of the output voltage remains across the resistor, and the published 1.8–2.2 V range applies at 20 mA rather than guaranteeing the drop at this lower current. Therefore neither exact current nor brightness is established by the nominal calculation.

At the resistor's −5% tolerance limit, R is 950 Ω. Even the deliberately unrealistic calculation V_LED = 0 V with an assumed 3.3 V output gives 3.47 mA and about 11.5 mW in the resistor if the resistor remains in series. This is a bounded resistor calculation, not short-circuit protection, a per-pin allowance, or a safety claim if the resistor is bypassed.

The RP2040 datasheet §5.5.3/Table 625 specifies a minimum high output voltage of 2.62 V at 3.3 V IOVDD under its listed configured 2/4/8/12 mA drive test conditions. Drive strength is not a current regulator. The datasheet's 50 mA aggregate GPIO/QSPI source-or-sink figure is a combined constraint, not permission to draw 50 mA from one pin. This bench uses the resistor and requires measurement rather than treating a nominal “3.3 V GPIO” label as an exact source.

Records, limits, and troubleshooting

Use notes/bench-log.csv for timestamped sensor observations with its unchanged schema. Use notes/led-bench-log.csv for the date, exact received LED and resistor, measured resistance, startup-pulse observation, commanded LED value, separately observed light, resistor voltage, inferred current, and notes. Keep commanded state and observed light separate: firmware can report led=1 even if the LED is reversed, misplaced, damaged, or not visibly bright.

If RPI-RP2 never appears, check the data cable and BOOTSEL procedure. If CIRCUITPY appears but imports fail, check the matching library-bundle major version, all three required library directories under lib, and both project Python files at the CIRCUITPY root. If no startup marker appears, inspect the serial traceback: imports must succeed before the pulse test can run. If startup commands are reported but no light is seen, power down and inspect polarity, distinct breadboard strips, the resistor path, and GP2/GND. If sensor initialization fails, power down and inspect the four sensor endpoints, solder, and exact BME280 identity. If CSV resumes but readings seem high, investigate Pico/USB heat, airflow, placement, settling time, and comparison evidence before applying any correction.

Unresolved physical evidence includes actual GPIO and resistor voltage, current, visible brightness, LED forward drop at this current, sensor address, sample timing tolerance, sensor offset, repeatability, self-heating, airflow response, altitude interpretation, humidity accuracy, and solder/jumper reliability. The design is an approachable lab interface, not a calibrated environmental instrument or certified indicator.

Sources and references

  1. Adafruit — original Raspberry Pi Pico RP2040 with loose headers (opens in a new tab)
  2. Adafruit — original Pico numbered pinout (opens in a new tab)
  3. Raspberry Pi — RP2040 datasheet (opens in a new tab)
  4. Adafruit — BME280 STEMMA QT breakout (opens in a new tab)
  5. Adafruit — BME280 power and signal pinouts (opens in a new tab)
  6. Adafruit — red 5 mm LED 25-pack (opens in a new tab)
  7. Adafruit — All About LEDs polarity guide (opens in a new tab)
  8. Adafruit — 1 kΩ ±5% 1/4 W resistor 25-pack (opens in a new tab)
  9. Adafruit — full-size breadboard (opens in a new tab)
  10. Adafruit — male/male jumper ribbon (opens in a new tab)
  11. Adafruit — USB-A to Micro-B data cable (opens in a new tab)
  12. Adafruit — USB-C to Micro-B data cable (opens in a new tab)
  13. Adafruit — backup 0.1-inch male header (opens in a new tab)
  14. Adafruit — BME280 header assembly (opens in a new tab)
  15. CircuitPython — original Raspberry Pi Pico UF2 (opens in a new tab)
  16. CircuitPython — library bundles (opens in a new tab)