Bootstrap of the project (M0). Sets up the monorepo, design docs, hardware BOM, the open API contract, component skeletons, licensing and CI, following the Default Workflow SOP. What changed: - CLAUDE.md + docs/: copied the Default Workflow so sessions load the SOP. - state/: PROJECT, ARCHITECTURE, DECISIONS, TODO, NOTES filled in for OpenScribe. ARCHITECTURE captures the four-part design (firmware, server, app, case) and the three sync paths; DECISIONS records the hardware, AI-stack, storage, app and licensing choices; TODO lays out milestones M1-M9. - hardware/BOM.md: two build options (compact XIAO ESP32-S3 Sense; dev ESP32-S3 + I2S mic + SD), wiring/pinout, indicative cost. - api/openapi.yaml: the completely open API (device + server surfaces), including recording list/download/delete and exports (wav/ogg/txt/srt/vtt/md/json). - firmware/: PlatformIO ESP32-S3 project, two board profiles, pin map, boot scaffold with module seams for M1-M4. - server/: FastAPI skeleton mirroring the OpenAPI, config for self-hosted MinIO, faster-whisper and Ollama; stub routes browsable at /docs. - app/, case/: Flutter app plan; parametric OpenSCAD enclosure. - Licensing: GPL-3.0 (code), CERN-OHL-S-2.0 (hardware), CC-BY-SA-4.0 (case/docs), REUSE-style LICENSES/ with SPDX headers; LICENSING.md explains the split. - CI: Forgejo Actions workflow builds firmware (both profiles) and lints/imports server. Why: - Everything self-hosted and openly licensed per the user's requirements: an open API, three sync paths (BLE control, WiFi transfer, independent WiFi upload on charge to generic cloud storage), and a full self-hosted transcription+summary stack. Notes: - No custom PCB in v1; off-the-shelf modules. Physical verification waits on parts. - Component code is stubs at M0; features land milestone by milestone, each as its own branch/PR per the workflow. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
91 lines
No EOL
2.8 KiB
OpenSCAD
91 lines
No EOL
2.8 KiB
OpenSCAD
// SPDX-License-Identifier: CC-BY-SA-4.0
|
|
//
|
|
// OpenScribe parametric enclosure (OpenSCAD).
|
|
//
|
|
// M0 scaffold: a parametric two-part shell sized from the board + battery dimensions, with
|
|
// the openings a recorder needs (mic port, button, USB, LED). Milestone M8 measures the
|
|
// chosen build from hardware/BOM.md, tunes these parameters, and adds mount/clip features
|
|
// and print-in-place tolerances. Render each half and export STL from there.
|
|
//
|
|
// Usage: set `part = "bottom" | "top" | "both"` and F5/F6 to preview/render.
|
|
|
|
/* [Which part] */
|
|
part = "both"; // ["both","bottom","top"]
|
|
|
|
/* [Board] (default: XIAO ESP32-S3 Sense - Build A) */
|
|
board_l = 21.0; // board length (mm)
|
|
board_w = 17.5; // board width (mm)
|
|
board_h = 3.5; // board thickness incl. components (mm)
|
|
|
|
/* [Battery] (default: ~502030 LiPo) */
|
|
batt_l = 30.0;
|
|
batt_w = 20.0;
|
|
batt_h = 5.5;
|
|
|
|
/* [Enclosure] */
|
|
wall = 1.6; // wall thickness (mm)
|
|
gap = 0.8; // clearance around internals (mm)
|
|
corner_r = 3.0; // outer corner radius (mm)
|
|
lid_lip = 1.2; // overlap between top and bottom (mm)
|
|
|
|
/* [Openings] */
|
|
mic_port_d = 1.2; // acoustic port diameter (mm)
|
|
usb_w = 9.5; usb_h = 3.4; // USB-C cutout
|
|
button_d = 4.0; // button plunger hole
|
|
led_d = 2.5; // LED light-pipe hole
|
|
|
|
// ---- derived internal cavity ----
|
|
inner_l = max(board_l, batt_l) + 2*gap;
|
|
inner_w = board_w + batt_w + 3*gap; // board beside battery
|
|
inner_h = max(board_h, batt_h) + 2*gap;
|
|
outer_l = inner_l + 2*wall;
|
|
outer_w = inner_w + 2*wall;
|
|
outer_h = inner_h + 2*wall;
|
|
|
|
module rrect(l, w, h, r) {
|
|
hull() for (x=[r, l-r], y=[r, w-r])
|
|
translate([x, y, 0]) cylinder(h=h, r=r, $fn=48);
|
|
}
|
|
|
|
module shell(height) {
|
|
difference() {
|
|
rrect(outer_l, outer_w, height, corner_r);
|
|
translate([wall, wall, wall])
|
|
rrect(outer_l-2*wall, outer_w-2*wall, height, max(0.5, corner_r-wall));
|
|
}
|
|
}
|
|
|
|
module bottom() {
|
|
h = outer_h*0.55;
|
|
difference() {
|
|
shell(h);
|
|
// USB-C cutout on one short side
|
|
translate([-1, (outer_w-usb_w)/2, wall+1])
|
|
cube([wall+2, usb_w, usb_h]);
|
|
}
|
|
}
|
|
|
|
module top() {
|
|
h = outer_h*0.55;
|
|
difference() {
|
|
shell(h);
|
|
// mic acoustic port (top face)
|
|
translate([outer_l*0.5, outer_w*0.5, h-wall-1])
|
|
cylinder(h=wall+2, d=mic_port_d, $fn=24);
|
|
// record button hole
|
|
translate([outer_l*0.75, outer_w*0.5, h-wall-1])
|
|
cylinder(h=wall+2, d=button_d, $fn=24);
|
|
// LED light-pipe hole
|
|
translate([outer_l*0.25, outer_w*0.5, h-wall-1])
|
|
cylinder(h=wall+2, d=led_d, $fn=24);
|
|
}
|
|
}
|
|
|
|
if (part == "both") {
|
|
bottom();
|
|
translate([0, outer_w + 6, 0]) top();
|
|
} else if (part == "bottom") {
|
|
bottom();
|
|
} else {
|
|
top();
|
|
} |