Add generate_examples.py script and update subproject commits
- Introduced a new script `generate_examples.py` to catalog board and sensor combinations, generating TypeScript example stubs for the frontend. - Updated subproject commit references for `qemu-lcgamboa`, `rp2040js`, and `wokwi-elements` to indicate they are in a dirty state.pull/47/head
parent
765a3ff711
commit
d170b4f7ea
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,346 @@
|
|||
"""
|
||||
generate_examples.py — Velxio example project generator helper
|
||||
================================================================
|
||||
This script catalogs board × sensor combinations and can generate
|
||||
TypeScript example stubs for inserting into
|
||||
frontend/src/data/examples.ts
|
||||
|
||||
Usage:
|
||||
python tools/generate_examples.py # print catalog summary
|
||||
python tools/generate_examples.py --generate # print TypeScript stubs
|
||||
python tools/generate_examples.py --shuffle # random combinations
|
||||
|
||||
Pin-name reference
|
||||
------------------
|
||||
Board component IDs used in wire objects:
|
||||
arduino-uno → component rendered by wokwi-arduino-uno
|
||||
nano-rp2040 → component rendered by wokwi-nano-rp2040-connect
|
||||
esp32 → component rendered by wokwi-esp32-devkit-v1
|
||||
esp32-c3 → custom ESP32-C3 DevKitM-1 canvas element
|
||||
|
||||
Board pin names for wires (from wokwi-elements *.ts pinInfo arrays):
|
||||
Arduino Uno:
|
||||
digital '2'…'13'
|
||||
analog 'A0'…'A5' (A4=I2C-SDA, A5=I2C-SCL)
|
||||
power '5V', 'GND', '3.3V'
|
||||
PWM capable 3, 5, 6, 9, 10, 11
|
||||
|
||||
Raspberry Pi Pico (nano-rp2040-connect element, GP-style convention):
|
||||
digital 'GP0'…'GP22'
|
||||
ADC 'A0'(GP26), 'A1'(GP27), 'A2'(GP28)
|
||||
I2C default 'GP4'(SDA), 'GP5'(SCL)
|
||||
power '3.3V', 'GND.1'
|
||||
PWM capable any GP pin
|
||||
|
||||
ESP32 DevKit-V1:
|
||||
digital 'D2','D4','D5','D12'…'D27','D32','D33'
|
||||
analog-only 'D34','D35','VP','VN'
|
||||
I2C 'D21'(SDA), 'D22'(SCL)
|
||||
power '3V3', 'VIN'(5V), 'GND.1'
|
||||
PWM capable most D pins except 34, 35
|
||||
|
||||
ESP32-C3 DevKitM-1:
|
||||
digital '0'…'21'
|
||||
I2C default '8'(SDA), '9'(SCL)
|
||||
power '3V3', 'GND.9'
|
||||
PWM capable most GPIO
|
||||
|
||||
Sensor pin names (from wokwi-elements *.ts pinInfo arrays):
|
||||
wokwi-dht22 VCC, SDA, NC, GND
|
||||
wokwi-hc-sr04 VCC, TRIG, ECHO, GND
|
||||
wokwi-pir-motion-sensor VCC, OUT, GND
|
||||
wokwi-servo GND, V+, PWM
|
||||
wokwi-photoresistor-sensor VCC, GND, DO, AO
|
||||
wokwi-ntc-temperature-sensor GND, VCC, OUT
|
||||
wokwi-buzzer 1, 2
|
||||
wokwi-analog-joystick VCC, VERT, HORZ, SEL, GND
|
||||
wokwi-mpu6050 INT, AD0, XCL, XDA, SDA, SCL, GND, VCC
|
||||
wokwi-potentiometer VCC, SIG, GND
|
||||
"""
|
||||
|
||||
import json
|
||||
import random
|
||||
import sys
|
||||
import textwrap
|
||||
from typing import NamedTuple
|
||||
|
||||
|
||||
# ── Board definitions ─────────────────────────────────────────────────────────
|
||||
|
||||
class Board(NamedTuple):
|
||||
id: str # component-id in wires
|
||||
board_type: str # boardType/boardFilter value
|
||||
board_type_key: str # boardType key in TS
|
||||
vcc_pin: str # 3.3 V or 5 V power pin
|
||||
gnd_pin: str # ground pin
|
||||
analog_pin: str # first ADC pin
|
||||
pwm_pin: str # a PWM-capable digital pin
|
||||
i2c_sda: str
|
||||
i2c_scl: str
|
||||
serial_baud: int
|
||||
|
||||
|
||||
BOARDS = [
|
||||
Board(
|
||||
id='arduino-uno', board_type='arduino-uno', board_type_key="'arduino-uno'",
|
||||
vcc_pin='5V', gnd_pin='GND', analog_pin='A0', pwm_pin='9',
|
||||
i2c_sda='A4', i2c_scl='A5', serial_baud=9600,
|
||||
),
|
||||
Board(
|
||||
id='nano-rp2040', board_type='raspberry-pi-pico', board_type_key="'raspberry-pi-pico'",
|
||||
vcc_pin='3.3V', gnd_pin='GND.1', analog_pin='A0', pwm_pin='GP15',
|
||||
i2c_sda='GP4', i2c_scl='GP5', serial_baud=115200,
|
||||
),
|
||||
Board(
|
||||
id='esp32', board_type='esp32', board_type_key="'esp32'",
|
||||
vcc_pin='3V3', gnd_pin='GND.1', analog_pin='D34', pwm_pin='D18',
|
||||
i2c_sda='D21', i2c_scl='D22', serial_baud=115200,
|
||||
),
|
||||
Board(
|
||||
id='esp32-c3', board_type='esp32-c3', board_type_key="'esp32-c3'",
|
||||
vcc_pin='3V3', gnd_pin='GND.9', analog_pin='', # no ADC in simple examples
|
||||
pwm_pin='8', i2c_sda='8', i2c_scl='9', serial_baud=115200,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
# ── Sensor definitions ────────────────────────────────────────────────────────
|
||||
|
||||
class Sensor(NamedTuple):
|
||||
id: str # e.g. 'dht22'
|
||||
wokwi_type: str # e.g. 'wokwi-dht22'
|
||||
name: str # human-readable
|
||||
category: str # 'sensors' | 'robotics' | etc.
|
||||
pins: dict # pin-role → pin-name on sensor element
|
||||
|
||||
|
||||
SENSORS = [
|
||||
Sensor(
|
||||
id='dht22', wokwi_type='wokwi-dht22',
|
||||
name='DHT22 Temperature & Humidity',
|
||||
category='sensors',
|
||||
pins={'vcc': 'VCC', 'gnd': 'GND', 'data': 'SDA'},
|
||||
),
|
||||
Sensor(
|
||||
id='hc-sr04', wokwi_type='wokwi-hc-sr04',
|
||||
name='HC-SR04 Ultrasonic Distance',
|
||||
category='sensors',
|
||||
pins={'vcc': 'VCC', 'gnd': 'GND', 'trig': 'TRIG', 'echo': 'ECHO'},
|
||||
),
|
||||
Sensor(
|
||||
id='pir', wokwi_type='wokwi-pir-motion-sensor',
|
||||
name='PIR Motion Sensor',
|
||||
category='sensors',
|
||||
pins={'vcc': 'VCC', 'gnd': 'GND', 'out': 'OUT'},
|
||||
),
|
||||
Sensor(
|
||||
id='servo', wokwi_type='wokwi-servo',
|
||||
name='Servo Motor',
|
||||
category='robotics',
|
||||
pins={'vcc': 'V+', 'gnd': 'GND', 'pwm': 'PWM'},
|
||||
),
|
||||
Sensor(
|
||||
id='photoresistor', wokwi_type='wokwi-photoresistor-sensor',
|
||||
name='Photoresistor Light Sensor',
|
||||
category='sensors',
|
||||
pins={'vcc': 'VCC', 'gnd': 'GND', 'do': 'DO', 'ao': 'AO'},
|
||||
),
|
||||
Sensor(
|
||||
id='ntc', wokwi_type='wokwi-ntc-temperature-sensor',
|
||||
name='NTC Thermistor Temperature',
|
||||
category='sensors',
|
||||
pins={'vcc': 'VCC', 'gnd': 'GND', 'out': 'OUT'},
|
||||
),
|
||||
Sensor(
|
||||
id='mpu6050', wokwi_type='wokwi-mpu6050',
|
||||
name='MPU-6050 Accelerometer/Gyroscope',
|
||||
category='sensors',
|
||||
pins={'vcc': 'VCC', 'gnd': 'GND', 'sda': 'SDA', 'scl': 'SCL'},
|
||||
),
|
||||
Sensor(
|
||||
id='joystick', wokwi_type='wokwi-analog-joystick',
|
||||
name='Analog Joystick',
|
||||
category='sensors',
|
||||
pins={'vcc': 'VCC', 'gnd': 'GND', 'vert': 'VERT', 'horz': 'HORZ', 'sel': 'SEL'},
|
||||
),
|
||||
Sensor(
|
||||
id='buzzer', wokwi_type='wokwi-buzzer',
|
||||
name='Piezo Buzzer',
|
||||
category='basics',
|
||||
pins={'p1': '1', 'p2': '2'},
|
||||
),
|
||||
Sensor(
|
||||
id='potentiometer', wokwi_type='wokwi-potentiometer',
|
||||
name='Potentiometer',
|
||||
category='sensors',
|
||||
pins={'vcc': 'VCC', 'gnd': 'GND', 'sig': 'SIG'},
|
||||
),
|
||||
]
|
||||
|
||||
SENSOR_BY_ID = {s.id: s for s in SENSORS}
|
||||
BOARD_BY_ID = {b.id: b for b in BOARDS}
|
||||
|
||||
|
||||
# ── Catalogue: which sensor works on which board ──────────────────────────────
|
||||
# Format: { board_id: [ (sensor_id, digital_pin_for_data, extra_pins), ... ] }
|
||||
# extra_pins are additional wires needed beyond VCC/GND
|
||||
|
||||
CATALOGUE: dict[str, list[tuple]] = {
|
||||
'arduino-uno': [
|
||||
('dht22', {'data': '7'}),
|
||||
('hc-sr04', {'trig': '9', 'echo': '10'}),
|
||||
('pir', {'out': '4'}),
|
||||
('servo', {'pwm': '9'}),
|
||||
('photoresistor', {'ao': 'A0', 'do': '8'}),
|
||||
('ntc', {'out': 'A1'}),
|
||||
],
|
||||
'nano-rp2040': [
|
||||
('dht22', {'data': 'GP7'}),
|
||||
('hc-sr04', {'trig': 'GP9', 'echo': 'GP10'}),
|
||||
('pir', {'out': 'GP14'}),
|
||||
('servo', {'pwm': 'GP15'}),
|
||||
('ntc', {'out': 'A0'}),
|
||||
('joystick', {'vert': 'A0', 'horz': 'A1', 'sel': 'GP14'}),
|
||||
],
|
||||
'esp32': [
|
||||
('dht22', {'data': 'D4'}),
|
||||
('hc-sr04', {'trig': 'D18', 'echo': 'D19'}),
|
||||
('pir', {'out': 'D5'}),
|
||||
('servo', {'pwm': 'D13'}),
|
||||
('mpu6050', {'sda': 'D21', 'scl': 'D22'}),
|
||||
('joystick', {'vert': 'D34', 'horz': 'D35', 'sel': 'D15'}),
|
||||
],
|
||||
'esp32-c3': [
|
||||
('dht22', {'data': '3'}),
|
||||
('hc-sr04', {'trig': '5', 'echo': '6'}),
|
||||
('pir', {'out': '7'}),
|
||||
('servo', {'pwm': '10'}),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
# ── Simple catalog printout ───────────────────────────────────────────────────
|
||||
|
||||
def print_catalog():
|
||||
print("=" * 60)
|
||||
print("Velxio Example Catalog")
|
||||
print("=" * 60)
|
||||
total = 0
|
||||
for board_id, combos in CATALOGUE.items():
|
||||
board = BOARD_BY_ID[board_id]
|
||||
print(f"\n{board.board_type} ({board_id})")
|
||||
print("-" * 40)
|
||||
for sensor_id, pins in combos:
|
||||
sensor = SENSOR_BY_ID[sensor_id]
|
||||
pin_str = ', '.join(f'{k}={v}' for k, v in pins.items())
|
||||
print(f" [{sensor.category:10s}] {sensor.name:35s} pins: {pin_str}")
|
||||
total += 1
|
||||
print(f"\nTotal combinations: {total}")
|
||||
|
||||
|
||||
# ── Random shuffle helper ─────────────────────────────────────────────────────
|
||||
|
||||
def shuffle_combos(seed: int = 42, count: int = 10):
|
||||
"""Return `count` random (board, sensor) pairs."""
|
||||
random.seed(seed)
|
||||
all_combos = []
|
||||
for board_id, combos in CATALOGUE.items():
|
||||
for sensor_id, pins in combos:
|
||||
all_combos.append((board_id, sensor_id, pins))
|
||||
random.shuffle(all_combos)
|
||||
return all_combos[:count]
|
||||
|
||||
|
||||
# ── TypeScript stub generator ─────────────────────────────────────────────────
|
||||
|
||||
def _ts_id(board_id: str, sensor_id: str) -> str:
|
||||
short = board_id.replace('arduino-', '').replace('nano-rp2040', 'pico') \
|
||||
.replace('esp32-c3', 'c3').replace('esp32', 'esp32')
|
||||
return f"{short}-{sensor_id.replace('-', '')}"
|
||||
|
||||
|
||||
def generate_stub(board_id: str, sensor_id: str, pins: dict) -> str:
|
||||
board = BOARD_BY_ID[board_id]
|
||||
sensor = SENSOR_BY_ID[sensor_id]
|
||||
ts_id = _ts_id(board_id, sensor_id)
|
||||
|
||||
# Wires
|
||||
wire_lines = []
|
||||
wire_idx = 0
|
||||
# VCC wire
|
||||
wire_lines.append(
|
||||
f" {{ id: '{ts_id}-vcc', start: {{ componentId: '{board.id}', pinName: '{board.vcc_pin}' }}, "
|
||||
f"end: {{ componentId: '{ts_id}-s', pinName: '{sensor.pins.get('vcc', 'VCC')}' }}, color: '#ff0000' }},"
|
||||
)
|
||||
wire_idx += 1
|
||||
# GND wire
|
||||
wire_lines.append(
|
||||
f" {{ id: '{ts_id}-gnd', start: {{ componentId: '{board.id}', pinName: '{board.gnd_pin}' }}, "
|
||||
f"end: {{ componentId: '{ts_id}-s', pinName: '{sensor.pins.get('gnd', 'GND')}' }}, color: '#000000' }},"
|
||||
)
|
||||
# Data wires
|
||||
for role, sensor_pin in sensor.pins.items():
|
||||
if role in ('vcc', 'gnd'):
|
||||
continue
|
||||
board_pin = pins.get(role, '?')
|
||||
wire_lines.append(
|
||||
f" {{ id: '{ts_id}-{role}', start: {{ componentId: '{board.id}', pinName: '{board_pin}' }}, "
|
||||
f"end: {{ componentId: '{ts_id}-s', pinName: '{sensor_pin}' }}, color: '#22aaff' }},"
|
||||
)
|
||||
|
||||
wires_block = '\n'.join(wire_lines)
|
||||
|
||||
stub = f""" {{
|
||||
id: '{ts_id}',
|
||||
title: '{board.board_type.title()}: {sensor.name}',
|
||||
description: '// TODO: add description',
|
||||
category: '{sensor.category}',
|
||||
difficulty: 'beginner',
|
||||
boardType: {board.board_type_key},
|
||||
boardFilter: {board.board_type_key},
|
||||
code: `// {board.board_type} — {sensor.name}
|
||||
// TODO: add Arduino code`,
|
||||
components: [
|
||||
{{ type: '{sensor.wokwi_type}', id: '{ts_id}-s', x: 430, y: 150, properties: {{}} }},
|
||||
],
|
||||
wires: [
|
||||
{wires_block}
|
||||
],
|
||||
}},"""
|
||||
return stub
|
||||
|
||||
|
||||
def generate_all_stubs():
|
||||
print("// === AUTO-GENERATED STUBS from tools/generate_examples.py ===\n")
|
||||
print("// Paste into exampleProjects[] in frontend/src/data/examples.ts\n")
|
||||
for board_id, combos in CATALOGUE.items():
|
||||
print(f"\n // ─── {BOARD_BY_ID[board_id].board_type} ───\n")
|
||||
for sensor_id, pins in combos:
|
||||
print(generate_stub(board_id, sensor_id, pins))
|
||||
print()
|
||||
|
||||
|
||||
# ── Entry point ───────────────────────────────────────────────────────────────
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = sys.argv[1:]
|
||||
if '--generate' in args or '--stubs' in args:
|
||||
generate_all_stubs()
|
||||
elif '--shuffle' in args:
|
||||
seed = int(args[args.index('--shuffle') + 1]) if '--shuffle' in args and len(args) > args.index('--shuffle') + 1 else 42
|
||||
combos = shuffle_combos(seed=seed, count=12)
|
||||
print(f"\nShuffled combinations (seed={seed}):\n")
|
||||
for board_id, sensor_id, pins in combos:
|
||||
b = BOARD_BY_ID[board_id]
|
||||
s = SENSOR_BY_ID[sensor_id]
|
||||
print(f" {b.board_type:25s} + {s.name}")
|
||||
print()
|
||||
print("Run with --generate to see TypeScript stubs.\n")
|
||||
else:
|
||||
print_catalog()
|
||||
print("""
|
||||
Usage:
|
||||
python tools/generate_examples.py # catalog summary
|
||||
python tools/generate_examples.py --generate # TypeScript stub output
|
||||
python tools/generate_examples.py --shuffle # random combo list
|
||||
""")
|
||||
Loading…
Reference in New Issue