refactor(examples): move Pico W WiFi examples to the pro overlay seam
The Pico W WiFi showcase examples are a paid-overlay feature now (the WiFi
engine moved to the overlay). Read them through a build-time `@pro` seam so the
SSR prerender + gallery + sitemap include them when built with the overlay, and
OSS gets an empty stub.
- data/examples.ts: import { proExamples } from '@pro/data/proExamples' (static,
build-time) instead of the local examples-picow-wifi.ts; delete that file.
- src/__pro_stub__/data/proExamples.ts: OSS no-op (empty list) for the @pro alias.
- vitest.config.ts: mirror the @pro alias (stub by default / overlay when
VITE_PRO_BUILD) so tests loading examples.ts resolve it.
- scripts/generate-sitemap.mjs: also parse <PRO_OVERLAY_PATH>/data/proExamples.ts
when building with the overlay (the script reads example IDs from source text,
so it can't follow the alias).
- Tests: drop the picow-wifi import/usage from the 5 OSS example tests (they
validate the OSS set now); prune the 4 obsolete picow netlist snapshots. The
overlay's proExamples get their own coverage in pro/.../__tests__/.
This commit is contained in:
parent
7db9e41278
commit
375b952d47
|
|
@ -57,6 +57,23 @@ const exampleIds = [
|
|||
...parseExampleIds(circuitSource),
|
||||
];
|
||||
|
||||
// Pro overlay examples (e.g. the Pico W WiFi showcase) live in
|
||||
// <PRO_OVERLAY_PATH>/data/proExamples.ts and are spread into examples.ts via the
|
||||
// `@pro` alias at build time. This script parses example IDs from source TEXT
|
||||
// (it never executes the module), so it can't follow the alias — read the
|
||||
// overlay file directly when building with the overlay. OSS builds skip this.
|
||||
if (process.env.VITE_PRO_BUILD && process.env.PRO_OVERLAY_PATH) {
|
||||
try {
|
||||
const proSource = readFileSync(
|
||||
resolve(process.env.PRO_OVERLAY_PATH, 'data/proExamples.ts'),
|
||||
'utf-8',
|
||||
);
|
||||
exampleIds.push(...parseExampleIds(proSource));
|
||||
} catch {
|
||||
// No overlay examples file — nothing to add.
|
||||
}
|
||||
}
|
||||
|
||||
const exampleUrls = exampleIds.map((id) => ({
|
||||
loc: `${DOMAIN}/examples/${id}`,
|
||||
lastmod: TODAY,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
// Open-source no-op stub for `@pro/data/proExamples` (see vite.config.ts).
|
||||
// OSS builds ship NO pro examples — the Pico W WiFi showcase is a paid overlay
|
||||
// feature, so the velxio-prod overlay replaces this with the real list at build
|
||||
// time (VITE_PRO_BUILD=true + PRO_OVERLAY_PATH). The static import in
|
||||
// data/examples.ts resolves here in OSS, contributing an empty spread.
|
||||
import type { ExampleProject } from '../../data/examples';
|
||||
|
||||
export const proExamples: ExampleProject[] = [];
|
||||
|
|
@ -3449,32 +3449,3 @@ R_autopull_n5 n5 0 100Meg
|
|||
.op
|
||||
.end"
|
||||
`;
|
||||
|
||||
exports[`netlist snapshot — picow-wifi (4 examples) > picow-wifi-async-led 1`] = `
|
||||
"* Velxio circuit
|
||||
.op
|
||||
.end"
|
||||
`;
|
||||
|
||||
exports[`netlist snapshot — picow-wifi (4 examples) > picow-wifi-relay-web-server 1`] = `
|
||||
"* Velxio circuit
|
||||
V_relay-led_sense n0 relay-led_sense_mid DC 0
|
||||
D_relay-led relay-led_sense_mid n1 LED_RED
|
||||
R_autopull_n0 n0 0 100Meg
|
||||
R_autopull_n1 n1 0 100Meg
|
||||
.model LED_RED D(Is=1e-20 N=1.7)
|
||||
.op
|
||||
.end"
|
||||
`;
|
||||
|
||||
exports[`netlist snapshot — picow-wifi (4 examples) > picow-wifi-servo-web 1`] = `
|
||||
"* Velxio circuit
|
||||
.op
|
||||
.end"
|
||||
`;
|
||||
|
||||
exports[`netlist snapshot — picow-wifi (4 examples) > picow-wifi-websocket-led 1`] = `
|
||||
"* Velxio circuit
|
||||
.op
|
||||
.end"
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import { analogExamples } from '../data/examples-analog';
|
|||
import { digitalExamples } from '../data/examples-digital';
|
||||
import { hundredDaysExamples } from '../data/examples-100-days';
|
||||
import { epaperExamples } from '../data/examples-displays-epaper';
|
||||
import { picowWifiExamples } from '../data/examples-picow-wifi';
|
||||
import { circuitExamples } from '../data/examples-circuits';
|
||||
import type { ExampleProject } from '../data/examples';
|
||||
|
||||
|
|
@ -30,7 +29,6 @@ const ALL_EXAMPLES: ExampleProject[] = [
|
|||
...digitalExamples,
|
||||
...hundredDaysExamples,
|
||||
...epaperExamples,
|
||||
...picowWifiExamples,
|
||||
...circuitExamples,
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import { analogExamples } from '../data/examples-analog';
|
|||
import { digitalExamples } from '../data/examples-digital';
|
||||
import { hundredDaysExamples } from '../data/examples-100-days';
|
||||
import { epaperExamples } from '../data/examples-displays-epaper';
|
||||
import { picowWifiExamples } from '../data/examples-picow-wifi';
|
||||
import { circuitExamples } from '../data/examples-circuits';
|
||||
import {
|
||||
stripBrandPrefix,
|
||||
|
|
@ -62,7 +61,6 @@ const ALL_EXAMPLE_SOURCES = {
|
|||
digital: digitalExamples,
|
||||
'100-days': hundredDaysExamples,
|
||||
'epaper-displays': epaperExamples,
|
||||
'picow-wifi': picowWifiExamples,
|
||||
circuits: circuitExamples,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { hundredDaysExamples } from '../data/examples-100-days';
|
||||
import { epaperExamples } from '../data/examples-displays-epaper';
|
||||
import { picowWifiExamples } from '../data/examples-picow-wifi';
|
||||
import { circuitExamples } from '../data/examples-circuits';
|
||||
import { exampleToBuildNetlistInput } from '../utils/exampleToBuildNetlistInput';
|
||||
import { solveInput } from './helpers/solveInput';
|
||||
|
|
@ -91,5 +90,4 @@ function buildSuite(bucket: string, examples: ExampleProject[]): void {
|
|||
|
||||
buildSuite('100-days', hundredDaysExamples);
|
||||
buildSuite('epaper-displays', epaperExamples);
|
||||
buildSuite('picow-wifi', picowWifiExamples);
|
||||
buildSuite('circuits', circuitExamples);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import { analogExamples } from '../data/examples-analog';
|
|||
import { digitalExamples } from '../data/examples-digital';
|
||||
import { hundredDaysExamples } from '../data/examples-100-days';
|
||||
import { epaperExamples } from '../data/examples-displays-epaper';
|
||||
import { picowWifiExamples } from '../data/examples-picow-wifi';
|
||||
import { circuitExamples } from '../data/examples-circuits';
|
||||
import { exampleToBuildNetlistInput } from '../utils/exampleToBuildNetlistInput';
|
||||
import { buildNetlist } from '../simulation/spice/NetlistBuilder';
|
||||
|
|
@ -62,7 +61,6 @@ const BUCKETS: Bucket[] = [
|
|||
{ name: 'digital', examples: digitalExamples },
|
||||
{ name: '100-days', examples: hundredDaysExamples },
|
||||
{ name: 'epaper', examples: epaperExamples },
|
||||
{ name: 'picow-wifi', examples: picowWifiExamples },
|
||||
{ name: 'circuits', examples: circuitExamples },
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import { analogExamples } from '../data/examples-analog';
|
|||
import { digitalExamples } from '../data/examples-digital';
|
||||
import { hundredDaysExamples } from '../data/examples-100-days';
|
||||
import { epaperExamples } from '../data/examples-displays-epaper';
|
||||
import { picowWifiExamples } from '../data/examples-picow-wifi';
|
||||
import { circuitExamples } from '../data/examples-circuits';
|
||||
import type { ExampleProject } from '../data/examples';
|
||||
import { BOARD_KIND_FQBN, type BoardKind } from '../types/board';
|
||||
|
|
@ -39,7 +38,6 @@ const ALL_EXAMPLES: ExampleProject[] = [
|
|||
...digitalExamples,
|
||||
...hundredDaysExamples,
|
||||
...epaperExamples,
|
||||
...picowWifiExamples,
|
||||
...circuitExamples,
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -1,368 +0,0 @@
|
|||
/**
|
||||
* Pico W WiFi showcase — curated examples that highlight Velxio's
|
||||
* new CYW43439 chip emulation (see frontend/src/simulation/cyw43/).
|
||||
*
|
||||
* Source projects come from
|
||||
* https://github.com/KritishMohapatra/100_Days_100_IoT_Projects
|
||||
* (cloned at third-party/100_Days_100_IoT_Projects/) — every example
|
||||
* here is a verbatim copy of the upstream `Main Files/main.py` for the
|
||||
* matching project, with the WiFi credentials replaced by the synthetic
|
||||
* `Velxio-GUEST` AP that the emulator advertises.
|
||||
*
|
||||
* Each example is wired up to load with:
|
||||
* boardType: 'pi-pico-w' ← triggers Cyw43Bridge attachment
|
||||
* languageMode: 'micropython' ← MicroPythonLoader
|
||||
* files: [{ name: 'main.py', ... }]
|
||||
*
|
||||
* The end-to-end harness that proves these work end-to-end lives at
|
||||
* test/test_Raspberry_Pi_Pico_W/test_code/tests/07_picow_iot_projects.test.ts
|
||||
*/
|
||||
|
||||
import type { ExampleProject } from './examples';
|
||||
|
||||
const TAGS_WIFI = ['100-days', 'pi-pico-w', 'micropython', 'wifi', 'cyw43'];
|
||||
|
||||
/** Replace placeholder SSID/password lines with our virtual AP. */
|
||||
function withVelxioGuest(source: string): string {
|
||||
return source
|
||||
.replace(/SSID\s*=\s*"[^"]*"/g, 'SSID = "Velxio-GUEST"')
|
||||
.replace(/ssid\s*=\s*"[^"]*"/g, 'ssid = "Velxio-GUEST"')
|
||||
.replace(/WIFI_SSID\s*=\s*"[^"]*"/g, 'WIFI_SSID = "Velxio-GUEST"')
|
||||
.replace(/PASSWORD\s*=\s*"[^"]*"/g, 'PASSWORD = ""')
|
||||
.replace(/password\s*=\s*"[^"]*"/g, 'password = ""')
|
||||
.replace(/PASS\s*=\s*"[^"]*"/g, 'PASS = ""')
|
||||
.replace(/WIFI_PASSWORD\s*=\s*"[^"]*"/g, 'WIFI_PASSWORD = ""');
|
||||
}
|
||||
|
||||
// ─── Project sources ─────────────────────────────────────────────────
|
||||
//
|
||||
// Pasted from upstream `Main Files/main.py`. Comments at the top of each
|
||||
// string credit the original author/repo. Anyone can re-extract these by
|
||||
// running `python test/test_100_days/_emit_examples_data.py`.
|
||||
|
||||
const ASYNC_LED_CONTROL_PY = withVelxioGuest(`# Pico W Async LED Control — MicroPython
|
||||
# Source: github.com/KritishMohapatra/100_Days_100_IoT_Projects
|
||||
# Project: Pico_W_Async_LED_Control_(MicroPython)
|
||||
#
|
||||
# Connects to Velxio-GUEST and runs a tiny async HTTP server on :80
|
||||
# that toggles the on-board LED via Pin('LED'). The LED is wired
|
||||
# through the CYW43439 chip — Velxio's new emulator picks up the
|
||||
# gpioout IOCTL and drives the LED in the canvas.
|
||||
|
||||
import uasyncio as asyncio
|
||||
import network
|
||||
from machine import Pin
|
||||
|
||||
SSID = "Velxio-GUEST"
|
||||
PASSWORD = ""
|
||||
|
||||
led = Pin("LED", Pin.OUT)
|
||||
led.off()
|
||||
|
||||
async def wifi_connect():
|
||||
wlan = network.WLAN(network.STA_IF)
|
||||
wlan.active(True)
|
||||
wlan.connect(SSID, PASSWORD)
|
||||
print("Connecting WiFi...")
|
||||
while not wlan.isconnected():
|
||||
await asyncio.sleep(0.5)
|
||||
ip = wlan.ifconfig()[0]
|
||||
print("IP:", ip)
|
||||
print("Open browser: http://%s/" % ip)
|
||||
|
||||
led_on = False
|
||||
|
||||
def page():
|
||||
# The board's onboard LED isn't drawn on the canvas, so show a big
|
||||
# state indicator here; the buttons reload so you can see it flip.
|
||||
color = "#22c55e" if led_on else "#666"
|
||||
label = "LED ON" if led_on else "LED OFF"
|
||||
return ("<!DOCTYPE html><html><head>"
|
||||
"<meta name=viewport content='width=device-width,initial-scale=1'></head>"
|
||||
"<body style='font-family:sans-serif;text-align:center;padding:24px;background:#fafafa'>"
|
||||
"<h2>Pico W Onboard LED</h2>"
|
||||
"<div style='margin:18px auto;width:170px;padding:26px 0;border-radius:14px;"
|
||||
"background:%s;color:#fff;font-size:24px;font-weight:bold'>%s</div>"
|
||||
"<button style='font-size:18px;padding:12px 28px;margin:6px' "
|
||||
"onclick=\\"fetch('on').then(()=>location.reload())\\">ON</button>"
|
||||
"<button style='font-size:18px;padding:12px 28px;margin:6px' "
|
||||
"onclick=\\"fetch('off').then(()=>location.reload())\\">OFF</button>"
|
||||
"</body></html>") % (color, label)
|
||||
|
||||
async def handle_client(reader, writer):
|
||||
global led_on
|
||||
request = (await reader.readline()).decode()
|
||||
while await reader.readline() != b"\\r\\n":
|
||||
pass
|
||||
if "GET /on" in request:
|
||||
led.on(); led_on = True
|
||||
elif "GET /off" in request:
|
||||
led.off(); led_on = False
|
||||
writer.write(("HTTP/1.1 200 OK\\r\\nContent-Type: text/html\\r\\nConnection: close\\r\\n\\r\\n" + page()).encode())
|
||||
await writer.drain()
|
||||
await writer.wait_closed()
|
||||
|
||||
async def main():
|
||||
await wifi_connect()
|
||||
await asyncio.start_server(handle_client, "0.0.0.0", 80)
|
||||
print("Server running on port 80")
|
||||
while True:
|
||||
await asyncio.sleep(1)
|
||||
|
||||
asyncio.run(main())
|
||||
`);
|
||||
|
||||
const RELAY_WEB_SERVER_PY = withVelxioGuest(`# IoT Relay Control Web Server — MicroPython
|
||||
# Source: github.com/KritishMohapatra/100_Days_100_IoT_Projects
|
||||
# Project: IoT_Relay_Control_Web_Server_(Raspberry_Pi_Pico_2W)
|
||||
#
|
||||
# A blocking-style HTTP server on port 80 that flips a relay on
|
||||
# GP2 in response to GET /on and GET /off. The server runs on the
|
||||
# IP that Velxio's emulator hands out (10.13.37.42).
|
||||
|
||||
import network
|
||||
import socket
|
||||
import machine
|
||||
import time
|
||||
|
||||
relay = machine.Pin(2, machine.Pin.OUT)
|
||||
# Active-high so the LED wired to GP2 on the canvas lights when ON.
|
||||
relay_state = 0
|
||||
relay.value(relay_state)
|
||||
|
||||
ssid = "Velxio-GUEST"
|
||||
password = ""
|
||||
|
||||
wlan = network.WLAN(network.STA_IF)
|
||||
wlan.active(True)
|
||||
wlan.connect(ssid, password)
|
||||
|
||||
print("Connecting...")
|
||||
while not wlan.isconnected():
|
||||
time.sleep(0.5)
|
||||
|
||||
ip = wlan.ifconfig()[0]
|
||||
print("Connected at:", ip)
|
||||
|
||||
s = socket.socket()
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
s.bind((ip, 80))
|
||||
s.listen(1)
|
||||
|
||||
print("Open browser: http://%s/" % ip)
|
||||
|
||||
def page():
|
||||
on = (relay_state == 1)
|
||||
color = "#22c55e" if on else "#666"
|
||||
label = "RELAY ON" if on else "RELAY OFF"
|
||||
return ("<html><head><meta name=viewport content='width=device-width,initial-scale=1'></head>"
|
||||
"<body style='font-family:sans-serif;text-align:center;padding:24px;background:#fafafa'>"
|
||||
"<h2>Pico W Relay (GP2)</h2>"
|
||||
"<div style='margin:18px auto;width:170px;padding:26px 0;border-radius:14px;"
|
||||
"background:%s;color:#fff;font-size:24px;font-weight:bold'>%s</div>"
|
||||
"<button style='font-size:18px;padding:12px 28px;margin:6px' "
|
||||
"onclick=\\"fetch('on').then(()=>location.reload())\\">ON</button>"
|
||||
"<button style='font-size:18px;padding:12px 28px;margin:6px' "
|
||||
"onclick=\\"fetch('off').then(()=>location.reload())\\">OFF</button>"
|
||||
"</body></html>") % (color, label)
|
||||
|
||||
# Wrap each client in try/except: a browser that drops the connection
|
||||
# mid-response would otherwise raise ECONNRESET and kill the server loop.
|
||||
while True:
|
||||
try:
|
||||
conn, addr = s.accept()
|
||||
request = str(conn.recv(1024))
|
||||
if "/on" in request:
|
||||
relay_state = 1; relay.value(relay_state)
|
||||
elif "/off" in request:
|
||||
relay_state = 0; relay.value(relay_state)
|
||||
conn.send("HTTP/1.1 200 OK\\r\\nContent-Type: text/html\\r\\n\\r\\n" + page())
|
||||
conn.close()
|
||||
except OSError:
|
||||
try:
|
||||
conn.close()
|
||||
except Exception:
|
||||
pass
|
||||
`);
|
||||
|
||||
const SERVO_WEB_PY = withVelxioGuest(`# Pico W Web Servo Controller — MicroPython
|
||||
# Source: github.com/KritishMohapatra/100_Days_100_IoT_Projects
|
||||
# Project: Pico_W_Web_Servo_Controller
|
||||
|
||||
import network
|
||||
import socket
|
||||
from machine import Pin, PWM
|
||||
import time
|
||||
|
||||
ssid = "Velxio-GUEST"
|
||||
password = ""
|
||||
|
||||
print("Connecting to WiFi...")
|
||||
sta = network.WLAN(network.STA_IF)
|
||||
sta.active(True)
|
||||
sta.connect(ssid, password)
|
||||
while not sta.isconnected():
|
||||
time.sleep(0.5)
|
||||
print("Connected!", sta.ifconfig()[0])
|
||||
|
||||
servo = PWM(Pin(15), freq=50)
|
||||
|
||||
def write_servo(angle):
|
||||
angle = max(0, min(180, angle))
|
||||
pulse_us = 500 + (2500 - 500) * (angle / 180)
|
||||
duty = int((pulse_us / 20000) * 65535)
|
||||
servo.duty_u16(duty)
|
||||
|
||||
def webpage(pos):
|
||||
return ("<html><body><h1>Servo {p}°</h1>"
|
||||
"<input type=range min=0 max=180 value={p} "
|
||||
"oninput=\\"fetch('?value='+this.value)\\"></body></html>").format(p=pos)
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
s.bind(('', 80))
|
||||
s.listen(5)
|
||||
|
||||
current_pos = 90
|
||||
write_servo(current_pos)
|
||||
print("Web server started. Open browser: http://%s/" % sta.ifconfig()[0])
|
||||
|
||||
while True:
|
||||
conn, addr = s.accept()
|
||||
request = conn.recv(1024).decode('utf-8')
|
||||
if "GET /?value=" in request:
|
||||
try:
|
||||
v = int(request.split("/?value=")[1].split(" ")[0])
|
||||
if 0 <= v <= 180:
|
||||
current_pos = v; write_servo(v)
|
||||
except (ValueError, IndexError):
|
||||
pass
|
||||
conn.send('HTTP/1.1 200 OK\\r\\nContent-Type: text/html\\r\\n\\r\\n')
|
||||
conn.sendall(webpage(current_pos).encode('utf-8'))
|
||||
conn.close()
|
||||
`);
|
||||
|
||||
const WS_LED_PY = withVelxioGuest(`# WebSocket LED Control — MicroPython
|
||||
# Source: github.com/KritishMohapatra/100_Days_100_IoT_Projects
|
||||
# Project: WebSocket_LED_Control_using_Raspberry_Pi_Pico_W
|
||||
|
||||
import socket, network, time, ubinascii, uhashlib
|
||||
from machine import Pin
|
||||
|
||||
led = Pin(15, Pin.OUT); led.value(0)
|
||||
|
||||
SSID = "Velxio-GUEST"
|
||||
PASSWORD = ""
|
||||
|
||||
def ws_accept(key):
|
||||
GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
return ubinascii.b2a_base64(uhashlib.sha1((key + GUID).encode()).digest()).strip().decode()
|
||||
|
||||
def ws_decode(data):
|
||||
if len(data) < 6: return ""
|
||||
payload_len = data[1] & 127
|
||||
mask = data[2:6]
|
||||
payload = data[6:6 + payload_len]
|
||||
return bytes(payload[i] ^ mask[i % 4] for i in range(len(payload))).decode()
|
||||
|
||||
wlan = network.WLAN(network.STA_IF); wlan.active(True); wlan.connect(SSID, PASSWORD)
|
||||
while not wlan.isconnected():
|
||||
time.sleep(1)
|
||||
print("Connected!", wlan.ifconfig()[0])
|
||||
|
||||
server = socket.socket()
|
||||
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
server.bind(("0.0.0.0", 80)); server.listen(1)
|
||||
|
||||
while True:
|
||||
conn, addr = server.accept()
|
||||
try:
|
||||
raw = conn.recv(1024).decode()
|
||||
if "Sec-WebSocket-Key" in raw:
|
||||
key = raw.split("Sec-WebSocket-Key: ")[1].split("\\r\\n")[0].strip()
|
||||
conn.send(("HTTP/1.1 101 Switching Protocols\\r\\nUpgrade: websocket\\r\\n"
|
||||
"Connection: Upgrade\\r\\nSec-WebSocket-Accept: %s\\r\\n\\r\\n" % ws_accept(key)))
|
||||
while True:
|
||||
data = conn.recv(1024)
|
||||
if not data: break
|
||||
msg = ws_decode(data)
|
||||
if msg == "ON": led.value(1); reply = "LED IS ON"
|
||||
elif msg == "OFF": led.value(0); reply = "LED IS OFF"
|
||||
else: reply = "OK"
|
||||
conn.send(bytearray([0x81, len(reply)]) + reply.encode())
|
||||
finally:
|
||||
conn.close()
|
||||
`);
|
||||
|
||||
// ─── Curated entries ─────────────────────────────────────────────────
|
||||
|
||||
export const picowWifiExamples: ExampleProject[] = [
|
||||
{
|
||||
id: 'picow-wifi-async-led',
|
||||
title: 'Pico W — Async LED control over Wi-Fi',
|
||||
description:
|
||||
'Pico W joins Velxio-GUEST then runs an async HTTP server on :80. /on and /off toggle the on-board LED through the CYW43 chip — the same path the real driver takes.',
|
||||
category: 'communication',
|
||||
difficulty: 'beginner',
|
||||
boardType: 'pi-pico-w',
|
||||
languageMode: 'micropython',
|
||||
files: [{ name: 'main.py', content: ASYNC_LED_CONTROL_PY }],
|
||||
code: '',
|
||||
components: [],
|
||||
wires: [],
|
||||
tags: TAGS_WIFI,
|
||||
},
|
||||
{
|
||||
id: 'picow-wifi-relay-web-server',
|
||||
title: 'Pico W — IoT relay web server',
|
||||
description:
|
||||
'Blocking HTTP server that drives a relay on GP2. Hit http://10.13.37.42/on and /off to flip it. Source: 100_Days_100_IoT_Projects/IoT_Relay_Control_Web_Server.',
|
||||
category: 'communication',
|
||||
difficulty: 'beginner',
|
||||
boardType: 'pi-pico-w',
|
||||
languageMode: 'micropython',
|
||||
files: [{ name: 'main.py', content: RELAY_WEB_SERVER_PY }],
|
||||
code: '',
|
||||
components: [
|
||||
// A red LED wired to GP2 so the relay state is visible on the canvas:
|
||||
// GP2 HIGH (relay ON) lights it. Driven via the wire (anode->GP2,
|
||||
// cathode->GND), the same path an Arduino LED uses.
|
||||
{ type: 'wokwi-led', id: 'relay-led', x: 380, y: 40, properties: { color: 'red', pin: 2 } },
|
||||
],
|
||||
wires: [
|
||||
{ id: 'w-relay-a', start: { componentId: 'pi-pico-w', pinName: 'GP2' }, end: { componentId: 'relay-led', pinName: 'A' }, color: '#ef4444' },
|
||||
{ id: 'w-relay-c', start: { componentId: 'relay-led', pinName: 'C' }, end: { componentId: 'pi-pico-w', pinName: 'GND.1' }, color: '#1f2937' },
|
||||
],
|
||||
tags: TAGS_WIFI.concat(['relay']),
|
||||
},
|
||||
{
|
||||
id: 'picow-wifi-servo-web',
|
||||
title: 'Pico W — Web servo controller',
|
||||
description:
|
||||
'Drives a servo on GP15 from a slider on a web page served by the Pico W. Source: 100_Days_100_IoT_Projects/Pico_W_Web_Servo_Controller.',
|
||||
category: 'robotics',
|
||||
difficulty: 'intermediate',
|
||||
boardType: 'pi-pico-w',
|
||||
languageMode: 'micropython',
|
||||
files: [{ name: 'main.py', content: SERVO_WEB_PY }],
|
||||
code: '',
|
||||
components: [],
|
||||
wires: [],
|
||||
tags: TAGS_WIFI.concat(['servo']),
|
||||
},
|
||||
{
|
||||
id: 'picow-wifi-websocket-led',
|
||||
title: 'Pico W — WebSocket-controlled LED',
|
||||
description:
|
||||
'Hand-rolled WebSocket server. Browser opens an upgrade request, then sends "ON"/"OFF" frames to toggle the LED on GP15. Source: 100_Days_100_IoT_Projects/WebSocket_LED_Control_using_Raspberry_Pi_Pico_W.',
|
||||
category: 'communication',
|
||||
difficulty: 'advanced',
|
||||
boardType: 'pi-pico-w',
|
||||
languageMode: 'micropython',
|
||||
files: [{ name: 'main.py', content: WS_LED_PY }],
|
||||
code: '',
|
||||
components: [],
|
||||
wires: [],
|
||||
tags: TAGS_WIFI.concat(['websocket']),
|
||||
},
|
||||
];
|
||||
|
|
@ -8,7 +8,12 @@ import { circuitExamples } from './examples-circuits';
|
|||
import { analogExamples } from './examples-analog';
|
||||
import { digitalExamples } from './examples-digital';
|
||||
import { hundredDaysExamples } from './examples-100-days';
|
||||
import { picowWifiExamples } from './examples-picow-wifi';
|
||||
// Pro overlay examples (the Pico W WiFi showcase) — resolves to the real list
|
||||
// when built with the overlay (VITE_PRO_BUILD), else an empty stub in OSS.
|
||||
// Static import so the build-time SSR prerender + gallery + sitemap pick them
|
||||
// up. See pro/frontend/src/pro/data/proExamples.ts (overlay) and
|
||||
// src/__pro_stub__/data/proExamples.ts (OSS no-op).
|
||||
import { proExamples } from '@pro/data/proExamples';
|
||||
import { epaperExamples } from './examples-displays-epaper';
|
||||
import { retroIntelExamples } from './examples-retro-intel';
|
||||
import { robotDesktopExamples } from './examples-robot-desktop';
|
||||
|
|
@ -9735,7 +9740,7 @@ export const exampleProjects: ExampleProject[] = [
|
|||
...analogExamples,
|
||||
...digitalExamples,
|
||||
...hundredDaysExamples,
|
||||
...picowWifiExamples,
|
||||
...proExamples,
|
||||
...epaperExamples,
|
||||
...retroIntelExamples,
|
||||
...robotDesktopExamples,
|
||||
|
|
|
|||
|
|
@ -22,11 +22,22 @@ import path from 'path';
|
|||
* used by overlay tests (e.g. pro/.../snapshot.test.ts importing
|
||||
* `@velxio/store/useEditorStore`) must be declared here too or
|
||||
* test files explode with "Cannot find package '@velxio/...'".
|
||||
* - `@pro` likewise mirrors vite.config.ts: it resolves to the OSS no-op
|
||||
* stub by default, or the real overlay when VITE_PRO_BUILD +
|
||||
* PRO_OVERLAY_PATH are set. data/examples.ts statically imports
|
||||
* `@pro/data/proExamples`, so without this alias every test that loads
|
||||
* examples.ts would explode with "Cannot find package '@pro/...'".
|
||||
*/
|
||||
const proOverlayPath =
|
||||
process.env.VITE_PRO_BUILD && process.env.PRO_OVERLAY_PATH
|
||||
? path.resolve(process.env.PRO_OVERLAY_PATH)
|
||||
: path.resolve(__dirname, 'src/__pro_stub__');
|
||||
|
||||
export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
'@velxio': path.resolve(__dirname, 'src'),
|
||||
'@pro': proOverlayPath,
|
||||
},
|
||||
},
|
||||
// Allow vitest to import test files / sources from outside this
|
||||
|
|
|
|||
Loading…
Reference in New Issue