- name
- add-component-v1
- description
- Adds a new I2C sensor component definition to the Wippersnapper_Components repository. Use this skill whenever the user wants to create a matching PR from the firmware repo, add a new sensor component, create a definition.json, add an image for a WipperSnapper I2C component, or even just mentions a sensor name in the context of WipperSnapper or Adafruit IO. Also use when the user says "add component", "matching PR", "new sensor", "component definition", or asks about what subcomponents or I2C addresses a sensor uses. Covers: research, definition.json creation, product image acquisition, CI validation, and PR creation. This skill is for the components repo only — firmware driver changes belong in Adafruit_Wippersnapper_Arduino (see the add-sensor-component-v1 skill there).
# Add I2C Sensor Component Definition to Wippersnapper_Components v1
This skill adds a new I2C sensor component to the `Wippersnapper_Components` repository.
Each component lives in `components/i2c/<sensor_name>/` and consists of:
1. `definition.json` — describes the sensor, its I2C addresses, and subcomponents
2. `image.jpg` (or `.png`) — product photo, 400x300px, 4:3 ratio, under 100KB
### Naming convention
- **lowercase** for the component folder name and all file names within it
- The folder name must exactly match the `strcmp()` string used in the firmware's
`WipperSnapper_I2C.cpp` `initI2CDevice()` method
- Example: `components/i2c/tmp119/`
Decide the canonical name in Step 0 and use it everywhere.
## Reference
The official Adafruit guide for this process:
- Human-readable: https://learn.adafruit.com/how-to-add-a-new-component-to-adafruit-io-wippersnapper?view=all
- Machine-readable: https://learn.adafruit.com/how-to-add-a-new-component-to-adafruit-io-wippersnapper.md?view=all
Fetch the `<guide-slug-without-page-path-qualifier>.md?view=all` version if you need more detail on any step.
## Arguments
Accepts a sensor name as argument (e.g. `/add-component-v1 TMP119`).
The user may also provide: datasheet URL, product page URL, learn guide URL, vendor name,
I2C addresses, and what the sensor measures. If not provided, research them.
The user may also reference a companion firmware PR that contains a suggested `definition.json`.
**Treat PR-provided definitions as hints, not as verified data.** Always run Step 0 research
independently — firmware PR authors often use GitHub library URLs instead of learn guides,
miss I2C addresses, or use suboptimal field values. Every field must be verified against
authoritative sources (product page, learn guide, datasheet) before use.
## Step 0 — Research the Sensor (MANDATORY before creating any files)
> **Do not skip this step.** Even if a firmware PR or the user supplies a complete
> `definition.json`, you MUST independently verify every field — especially `documentationURL`
> (must be a learn guide for Adafruit products, not a GitHub repo) and `i2cAddresses` (must
> include all ADDR pin combinations). Copying unverified values from PRs has caused bad PRs.
### Check for duplicates first
Before anything else, check `components/i2c/` to see if a component already exists for this
sensor. If it does, tell the user — they may want to update it rather than create a new one.
### Gather sensor information
| What | How to find it |
|------|---------------|
| **Product page** | Web search "adafruit \<SENSOR\>" to find `https://www.adafruit.com/product/<ID>`. For non-Adafruit products, find the manufacturer's product page or a distributor listing (DigiKey, Mouser, etc.) |
| **Learn guide** | Found on the Adafruit product page HTML (grep for `learn.adafruit.com`). Fetch the `.md?view=all` version for easy reading. For non-Adafruit products, use the manufacturer's documentation or datasheet |
| **Vendor** | The chip manufacturer (e.g. "Bosch", "Texas Instruments", "Sensirion", "OMRON", "Melexis"), NOT "Adafruit" unless Adafruit designed the chip |
| **I2C addresses** | Datasheet, learn guide, or Arduino library. Include ALL possible addresses from ADDR pin configurations. Also check https://learn.adafruit.com/i2c-addresses/the-list |
| **What it measures** | Map each reading to a subcomponent type from the reference table below |
| **Documentation URL** | Prefer: Adafruit learn guide > manufacturer docs page/wiki > datasheet URL |
| **Closest existing component** | Browse `components/i2c/` for a sensor in the same family or with identical reading types — use it as a template |
### Valid subcomponent types
These are the only valid values (must match the pattern in `components/i2c/schema.json`):
| Subcomponent | What it measures | SI unit |
|---|---|---|
| `ambient-temp` | Ambient temperature | degC |
| `ambient-temp-fahrenheit` | Ambient temperature | degF |
| `object-temp` | Object/thermocouple temp | degC |
| `object-temp-fahrenheit` | Object/thermocouple temp | degF |
| `humidity` | Relative humidity | %RH |
| `pressure` | Barometric pressure | hPa |
| `altitude` | Relative altitude | m |
| `co2` | CO2 concentration | ppm |
| `eco2` | Estimated CO2 | ppm |
| `tvoc` | Total VOCs | ppb |
| `gas-resistance` | Gas resistance | ohm |
| `light` | Light level | lux |
| `lux` | Light level (lux) | lux |
| `proximity` | Proximity | unitless |
| `voltage` | Voltage | V |
| `current` | Current | A |
| `color` | Color | unitless |
| `raw` | Raw data | unitless |
| `unitless-percent` | Percentage | % |
| `pm10-std` | PM1.0 standard | ug/m3 |
| `pm25-std` | PM2.5 standard | ug/m3 |
| `pm100-std` | PM10.0 standard | ug/m3 |
| `pm10-env` | PM1.0 environmental | ug/m3 |
| `pm25-env` | PM2.5 environmental | ug/m3 |
| `pm100-env` | PM10.0 environmental | ug/m3 |
| `accelerometer` | Acceleration | m/s2 |
| `magnetic-field` | Magnetic field | uT |
| `orientation` | Orientation | degrees |
| `gyroscope` | Angular velocity | rad/s |
| `gravity` | Gravity | m/s2 |
| `acceleration` | Linear acceleration | m/s2 |
| `rotation` | Rotation | rad/s |
| `voc-index` | VOC index | unitless |
| `nox-index` | NOx index | unitless |
**Temperature sensors** almost always include BOTH `ambient-temp` AND `ambient-temp-fahrenheit`.
The firmware base class handles the degC-to-degF conversion automatically — the driver only
implements the Celsius version.
## Step 1 — Create the component folder and definition.json
### Folder naming
- **Lowercase only** — CI rejects uppercase characters in paths
- Folder name must match the `strcmp()` string used in the firmware's `WipperSnapper_I2C.cpp`
- Example: `components/i2c/tmp119/`
### definition.json format
```json
{
"displayName": "<Sensor Display Name>",
"vendor": "<Chip Manufacturer>",
"productURL": "https://www.adafruit.com/product/<ID>",
"documentationURL": "https://learn.adafruit.com/<guide-slug>",
"published": false,
"i2cAddresses": ["0x48"],
"subcomponents": ["ambient-temp", "ambient-temp-fahrenheit"]
}
```
#### Field rules
| Field | Required | Notes |
|-------|----------|-------|
| `displayName` | Yes | 3-24 characters. Usually the chip name (e.g. "TMP119", "BME280") |
| `vendor` | Yes | 3-24 characters. The chip manufacturer, not "Adafruit" |
| `i2cAddresses` | Yes | Array of hex strings. Include ALL possible addresses |
| `subcomponents` | Yes | Array of sensor type strings or objects |
| `productURL` | No | URI to product page (see URL guidance below) |
| `documentationURL` | No | URI to documentation (see URL guidance below) |
| `published` | No | Always set to `false` for new contributions. Adafruit sets `true` after release |
| `description` | No | 3-255 characters. Brief description of capabilities |
#### URL guidance
**`productURL`** — where someone can buy or learn about the product:
- **Adafruit products:** `https://www.adafruit.com/product/<ID>` (preferred)
- **Non-Adafruit products:** Use distributor listings (DigiKey, Mouser) or manufacturer product
pages. Examples from existing components:
- DigiKey: `https://www.digikey.com/en/products/detail/...` (used by SEN5x, SHT20, MLX90632)
- Manufacturer: `http://www.aosong.com/en/products-60.html` (used by AHT21)
**`documentationURL`** — technical docs for the sensor:
- **Adafruit products:** Adafruit learn guide (preferred). Find it on the product page
(search for `learn.adafruit.com`). **Never use a GitHub library repo URL** (e.g.
`github.com/adafruit/Adafruit_<SENSOR>`) — that is source code, not documentation.
- **Non-Adafruit products:** Manufacturer documentation page, wiki, or datasheet PDF URL.
Examples: Sensirion datasheet PDFs, OMRON user manuals
- Third-party domain URLs may initially fail CI URL validation until a maintainer adds the
domain to the allowlist — note this in the PR if using a non-standard domain
#### Subcomponent formats
**Simple format** — when the sensor type name is self-explanatory:
```json
"subcomponents": ["ambient-temp", "ambient-temp-fahrenheit", "pressure"]
```
**Object format** — when a custom display name is needed for clarity:
```json
"subcomponents": [
{ "displayName": "Ambient Light", "sensorType": "light" },
{ "displayName": "UV Count", "sensorType": "raw" }
]
```
Use objects when:
1. **Type name is ambiguous** — "light" could mean visible, UV, or IR. `displayName` clarifies
in the UI
2. **Two readings share the same physical type** — v1 schema forbids duplicate `sensorType`.
Use `"raw"` for the second with a descriptive `displayName` (e.g. LTR-329: `"light"` for
ambient, `"raw"` with `displayName: "Infrared"` for IR)
3. **Non-standard units** — sensor reports in a unit that doesn't match the Adafruit_Sensor SI
unit for that type; use `raw` or `unitless-percent` with a descriptive `displayName`
4. **Clarity** — when the auto-generated UI label would be confusing. Compare existing components
that use the same types for reference
When using `"raw"` as a stand-in, the driver must implement `getEventRaw()` for that reading.
**Examples from existing components:**
- **TMP117** (temp only): `["ambient-temp", "ambient-temp-fahrenheit"]`
- **BME280** (multi): `["ambient-temp", "ambient-temp-fahrenheit", "humidity", "pressure", "altitude"]`
- **SGP41** (VOC + NOx + raw): `["voc-index", "nox-index", {"displayName": "Raw VOC Ticks (Reference)", "sensorType": "raw"}]`
- **D6T-1A** (ambient + object temp, all objects for clarity):
```json
[
{"displayName": "Ambient Temperature (°C)", "sensorType": "ambient-temp"},
{"displayName": "Ambient Temperature (°F)", "sensorType": "ambient-temp-fahrenheit"},
{"displayName": "Measured Object Temp (°C)", "sensorType": "object-temp"},
{"displayName": "Measured Object Temp (°F)", "sensorType": "object-temp-fahrenheit"}
]
```
- **SEN55** (many readings, simple strings): `["ambient-temp", "ambient-temp-fahrenheit", "humidity", "pm10-std", "pm25-std", "pm100-std", "voc-index", "nox-index"]`
### Schema validation
The definition.json must validate against `components/i2c/schema.json`. Key constraints:
- `displayName`: string, 3-24 chars
- `vendor`: string, 3-24 chars
- `i2cAddresses`: array of strings
- `subcomponents`: array — each item is either a valid sensor type string OR an object with
required `displayName` (string) and `sensorType` (valid sensor type string), optional `defaultPeriod`
- No additional properties allowed (`additionalProperties: false`)
## Step 2 — Add product image
### Requirements (enforced by CI)
| Property | Requirement |
|----------|-------------|
| Dimensions | Exactly 400x300 pixels |
| Aspect ratio | Must be exactly 4:3 |
| File size | Under 100KB (102400 bytes) |
| Format | `.jpg`, `.jpeg`, `.png`, `.gif`, or `.svg` |
| Filename | `image.<ext>` (lowercase) |
| Mimetype | Must match file extension |
### Choosing the right source image
**For Adafruit products:**
1. **Scrape all image URLs from the product page:** Fetch `https://www.adafruit.com/product/<PID>`
and extract all `cdn-shop.adafruit.com` image URLs. The product page gallery contains every
available shot — don't guess image numbers, as they are not necessarily contiguous.
2. **CRITICAL — Always use the `/original/` CDN URL, NOT `970x728` or `640x480`.**
The Adafruit CDN URL contains a resolution prefix. You MUST replace it with `original`
to get the highest-resolution source for downscaling. Downloading a pre-scaled version
(e.g. `970x728`) produces a blurry 400x300 result.
- **USE THIS:** `https://cdn-shop.adafruit.com/original/<PID>-NN.jpg`
- NOT: `https://cdn-shop.adafruit.com/970x728/<PID>-NN.jpg`
- NOT: `https://cdn-shop.adafruit.com/640x480/<PID>-NN.jpg`
- For each image URL scraped from the product page, replace the resolution part
(e.g. `970x728`, `640x480`) with `original` before downloading
3. **Check all available shots** from the scraped URLs — pick the slight-angle / isometric
close-up of the breakout board with a plain background (this is the standard Adafruit product
photo style, typically image `00`). Avoid lifestyle shots, shots with other boards or
accessories in the frame, or images where the board is very small in the frame.
4. Compare with existing component images (e.g. `components/i2c/sgp41/image.jpg`) for the
expected style: close-up, slight angle, plain dark background, board well-centered.
**For non-Adafruit products:**
If no Adafruit CDN image is available, try:
1. The manufacturer's product page for an official product photo
2. Distributor listings (DigiKey, Mouser) which often have product images
3. Ask the user to provide an image
Whatever the source, the image must meet the same CI requirements (400x300, 4:3, under 100KB).
### Centering and cropping
**The board must be visually centered in the final image.** This means:
- The **top** and **bottom** of the board should be approximately the same distance from the
top and bottom edges of the image
- The board should be **horizontally centered** in the frame
- There should be a comfortable amount of dead space around the board so it doesn't feel
cropped or cramped in the UI
The source image from Adafruit CDN often has the board slightly off-center (typically shifted
upward). To correct this:
Auf GitHub ansehen