Firmware for the Seeed Studio XIAO ESP32C6 microcontroller providing BLE-controlled monitoring and LED features.
- Board: Seeed Studio XIAO ESP32C6
- Framework: ESP-IDF via PlatformIO
| Pin | GPIO | Function |
|---|---|---|
| D3 | GPIO21 | WS2814 RGBW LED strip data (100 addressable pixels) |
| D9 | GPIO20 | BLE connected indicator LED (active low) |
| D9 | GPIO15 | Status LED (blinking) |
| A0 | GPIO0 | Analog input 0 (with voltage divider) |
| A1 | GPIO1 | Analog input 1 (with voltage divider) |
| - | GPIO14 | Antenna switch (using onboard antenna) |
Note: GPIO10 (D10) is tied to the internal flash on ESP32-C6 and cannot be used as a general GPIO output.
Pin Label -> GPIO Number -> ADC Channel (if applicable)
A0 = GPIO0 = ADC1_CH0
A1 = GPIO1 = ADC1_CH1
A2 = GPIO2 = ADC1_CH2
D0 = GPIO0 = ADC1_CH0
D1 = GPIO1 = ADC1_CH1
D2 = GPIO2 = ADC1_CH2
D3 = GPIO21 = (no ADC)
D4 = GPIO22 = (no ADC)
D5 = GPIO23 = (no ADC)
D6 = GPIO16 = (no ADC)
D7 = GPIO17 = (no ADC)
D8 = GPIO19 = (no ADC)
D9 = GPIO20 = (no ADC)
D10 = GPIO10 = UNUSABLE (flash SPI)
Analog inputs A0 and A1 have external voltage dividers:
- Top resistor: 82k ohm
- Bottom resistor: 20k ohm
- Division ratio: 5.1
- Max measurable voltage: ~16.8V (3.3V * 5.1)
- Device Name:
BoatMonitor - Service UUID:
0x00FF(16-bit)
Controls the status LED on/off state.
| Property | Value |
|---|---|
| UUID | 0xFF01 |
| Permissions | Read, Write |
| Data Length | 1 byte |
Data Format:
0x00= LED off0x01= LED on (any non-zero value turns on)
Example:
Write: [0x01] // Turn LED on
Write: [0x00] // Turn LED off
Read: [0x01] // LED is currently on
Controls the blink rate of the status LED.
| Property | Value |
|---|---|
| UUID | 0xFF02 |
| Permissions | Read, Write |
| Data Length | 1 byte |
Data Format:
- Value range: 0-100
- Delay calculation:
value * 10milliseconds per half-cycle 0= LED stays solid (no blinking)50= 500ms on, 500ms off (1 Hz)100= 1000ms on, 1000ms off (0.5 Hz)
Example:
Write: [0x32] // Set blink rate to 50 (500ms delay)
Write: [0x00] // Solid on (no blink)
Read: [0x32] // Current rate is 50
Reads voltage from both analog inputs A0 (GPIO0) and A1 (GPIO1).
| Property | Value |
|---|---|
| UUID | 0xFF03 |
| Permissions | Read only |
| Data Length | 4 bytes |
Data Format (Big Endian):
Byte 0: A0 voltage high byte
Byte 1: A0 voltage low byte
Byte 2: A1 voltage high byte
Byte 3: A1 voltage low byte
Values are in millivolts with voltage divider applied.
Example:
Read: [0x2E, 0xE0, 0x17, 0x70]
A0 = 0x2EE0 = 12000 mV (12.0V)
A1 = 0x1770 = 6000 mV (6.0V)
Parsing (pseudocode):
a0_mv = (data[0] << 8) | data[1]
a1_mv = (data[2] << 8) | data[3]
a0_volts = a0_mv / 1000.0
a1_volts = a1_mv / 1000.0Controls the WS2814 RGBW LED strip (100 addressable pixels on D3/GPIO21).
| Property | Value |
|---|---|
| UUID | 0xFF04 |
| Permissions | Read, Write |
| Data Length | 5 bytes |
Data Format:
Byte 0: On/Off (0x00=off, 0x01=on)
Byte 1: Red (0-255)
Byte 2: Green (0-255)
Byte 3: Blue (0-255)
Byte 4: White (0-255) - Warm white LED channel
All 100 pixels are set to the same color. The 4-byte legacy format (without white) is also supported.
Example:
Write: [0x01, 0xFF, 0x00, 0x00, 0x00] // Turn on, full red
Write: [0x01, 0x00, 0xFF, 0x00, 0x00] // Turn on, full green
Write: [0x01, 0x00, 0x00, 0xFF, 0x00] // Turn on, full blue
Write: [0x01, 0x00, 0x00, 0x00, 0xFF] // Turn on, warm white only
Write: [0x01, 0xFF, 0xFF, 0xFF, 0xFF] // Turn on, full RGBW
Write: [0x01, 0xFF, 0x00, 0x00] // Legacy 4-byte format (no white)
Write: [0x00, 0x00, 0x00, 0x00, 0x00] // Turn off
Write: [0x00] // Turn off (1 byte shorthand)
Read: [0x01, 0xFF, 0x00, 0x00, 0x00] // Strip is on, color is red
GPIO20 (D9) operates as an active-low indicator:
- LOW (0V) when a BLE client is connected - LED ON
- HIGH (3.3V) when disconnected - LED OFF
Connect an LED with anode to 3.3V and cathode through a resistor to D9 for visual connection status.
# Build
pio run
# Upload
pio run -t upload
# Monitor serial output
pio device monitor| Characteristic | UUID | R/W | Bytes | Description |
|---|---|---|---|---|
| LED On/Off | 0xFF01 | R/W | 1 | Status LED on/off |
| Blink Rate | 0xFF02 | R/W | 1 | Blink delay (0-100) |
| Analog Inputs | 0xFF03 | R | 4 | A0 and A1 in mV |
| LED Strip | 0xFF04 | R/W | 5 | Strip on/off + RGBW |
import asyncio
from bleak import BleakClient
DEVICE_NAME = "BoatMonitor"
SERVICE_UUID = "000000ff-0000-1000-8000-00805f9b34fb"
CHAR_LED_UUID = "0000ff01-0000-1000-8000-00805f9b34fb"
CHAR_BLINK_UUID = "0000ff02-0000-1000-8000-00805f9b34fb"
CHAR_ANALOG_UUID = "0000ff03-0000-1000-8000-00805f9b34fb"
CHAR_STRIP_UUID = "0000ff04-0000-1000-8000-00805f9b34fb"
async def main():
async with BleakClient("XX:XX:XX:XX:XX:XX") as client:
# Turn on status LED
await client.write_gatt_char(CHAR_LED_UUID, bytes([0x01]))
# Set blink rate to 500ms
await client.write_gatt_char(CHAR_BLINK_UUID, bytes([50]))
# Read analog inputs
data = await client.read_gatt_char(CHAR_ANALOG_UUID)
a0_mv = (data[0] << 8) | data[1]
a1_mv = (data[2] << 8) | data[3]
print(f"A0: {a0_mv}mV, A1: {a1_mv}mV")
# Set LED strip to blue (RGBW format: on, R, G, B, W)
await client.write_gatt_char(CHAR_STRIP_UUID, bytes([0x01, 0x00, 0x00, 0xFF, 0x00]))
asyncio.run(main())