Initial design: ESP32-S3 presence sensor with camera, mmWave, PIR, temp/humidity, light
- KiCad schematic and PCB layout (45x35mm board) - Full BOM with JLCPCB part numbers - ESPHome firmware configuration - 3D-printable wall-mount enclosure (OpenSCAD + STL) - Pin mapping and power budget documentation
This commit is contained in:
11762
enclosure/body.stl
Normal file
11762
enclosure/body.stl
Normal file
File diff suppressed because it is too large
Load Diff
2
enclosure/body_only.scad
Normal file
2
enclosure/body_only.scad
Normal file
@@ -0,0 +1,2 @@
|
||||
include <enclosure.scad>;
|
||||
// Only body is rendered (default render includes both)
|
||||
185
enclosure/enclosure.scad
Normal file
185
enclosure/enclosure.scad
Normal file
@@ -0,0 +1,185 @@
|
||||
// ============================================
|
||||
// Presence Sensor Wall-Mount Enclosure
|
||||
// ESP32-S3 + OV5640 + LD2410C + AM312 + SHT41 + BH1750
|
||||
// Board: 45 x 35 mm
|
||||
// ============================================
|
||||
|
||||
// Dimensions (mm)
|
||||
pcb_w = 45; // PCB width
|
||||
pcb_h = 35; // PCB height
|
||||
pcb_t = 1.6; // PCB thickness
|
||||
|
||||
wall = 1.8; // Wall thickness
|
||||
tolerance = 0.3; // Fit tolerance
|
||||
bottom_gap = 3; // Space below PCB for solder joints
|
||||
top_gap = 12; // Space above PCB for components + modules
|
||||
lid_lip = 1.5; // Lid overlap lip
|
||||
|
||||
// Derived
|
||||
inner_w = pcb_w + tolerance * 2;
|
||||
inner_h = pcb_h + tolerance * 2;
|
||||
inner_d = bottom_gap + pcb_t + top_gap;
|
||||
outer_w = inner_w + wall * 2;
|
||||
outer_h = inner_h + wall * 2;
|
||||
outer_d = inner_d + wall; // Open top (lid covers)
|
||||
|
||||
// Screw post dimensions
|
||||
post_d = 4.5; // Post outer diameter
|
||||
screw_d = 2.2; // M2 screw hole
|
||||
post_h = bottom_gap; // Height to PCB level
|
||||
|
||||
// Component positions (from bottom-left of PCB)
|
||||
cam_x = pcb_w / 2; // Camera centered horizontally
|
||||
cam_y = pcb_h - 5; // Camera near top
|
||||
cam_hole_w = 10; // Camera lens window
|
||||
cam_hole_h = 10;
|
||||
|
||||
pir_x = 12; // PIR left of center
|
||||
pir_y = pcb_h - 20;
|
||||
pir_hole_d = 10; // AM312 dome diameter
|
||||
|
||||
light_x = 30; // BH1750 right of center
|
||||
light_y = pcb_h - 20;
|
||||
light_hole_d = 4; // Small window for light sensor
|
||||
|
||||
mmwave_x = pcb_w / 2; // LD2410C centered
|
||||
mmwave_y = 8; // Near bottom
|
||||
mmwave_slot_w = 8; // Slot for radar signal
|
||||
mmwave_slot_h = 36;
|
||||
|
||||
usbc_x = pcb_w / 2; // USB-C centered bottom
|
||||
usbc_w = 10;
|
||||
usbc_h = 4;
|
||||
|
||||
vent_slot_w = 1.5;
|
||||
vent_slot_h = 8;
|
||||
|
||||
// ============================================
|
||||
// Main body
|
||||
// ============================================
|
||||
module body() {
|
||||
difference() {
|
||||
// Outer shell
|
||||
rounded_box(outer_w, outer_h, outer_d, 3);
|
||||
|
||||
// Inner cavity
|
||||
translate([wall, wall, wall])
|
||||
rounded_box(inner_w, inner_h, inner_d + 1, 2);
|
||||
|
||||
// Camera window (front face - top)
|
||||
translate([wall + tolerance + cam_x - cam_hole_w/2,
|
||||
wall + tolerance + cam_y - cam_hole_h/2,
|
||||
-1])
|
||||
rounded_box(cam_hole_w, cam_hole_h, wall + 2, 2);
|
||||
|
||||
// PIR window (front face)
|
||||
translate([wall + tolerance + pir_x,
|
||||
wall + tolerance + pir_y,
|
||||
-1])
|
||||
cylinder(h=wall+2, d=pir_hole_d, $fn=32);
|
||||
|
||||
// Light sensor window (front face)
|
||||
translate([wall + tolerance + light_x,
|
||||
wall + tolerance + light_y,
|
||||
-1])
|
||||
cylinder(h=wall+2, d=light_hole_d, $fn=32);
|
||||
|
||||
// USB-C cutout (bottom edge)
|
||||
translate([wall + tolerance + usbc_x - usbc_w/2,
|
||||
-1,
|
||||
wall + bottom_gap - 1])
|
||||
cube([usbc_w, wall + 2, usbc_h + 2]);
|
||||
|
||||
// Ventilation slots (sides - for SHT41 airflow)
|
||||
for (i = [0:3]) {
|
||||
// Left side
|
||||
translate([-1,
|
||||
wall + 5 + i * (vent_slot_h + 2),
|
||||
wall + bottom_gap + pcb_t + 2])
|
||||
cube([wall + 2, vent_slot_h, vent_slot_w]);
|
||||
// Right side
|
||||
translate([outer_w - wall - 1,
|
||||
wall + 5 + i * (vent_slot_h + 2),
|
||||
wall + bottom_gap + pcb_t + 2])
|
||||
cube([wall + 2, vent_slot_h, vent_slot_w]);
|
||||
}
|
||||
|
||||
// mmWave radar slot (through back wall for better signal)
|
||||
translate([wall + tolerance + mmwave_x - mmwave_slot_w/2,
|
||||
wall + tolerance + mmwave_y - mmwave_slot_h/2,
|
||||
outer_d - wall - 0.5])
|
||||
rounded_box(mmwave_slot_w, mmwave_slot_h, wall + 1, 1);
|
||||
|
||||
// Wall mount screw slots (keyhole on back)
|
||||
translate([outer_w/2, outer_h * 0.3, outer_d - wall - 1])
|
||||
wall_mount_keyhole();
|
||||
translate([outer_w/2, outer_h * 0.7, outer_d - wall - 1])
|
||||
wall_mount_keyhole();
|
||||
}
|
||||
|
||||
// PCB support posts
|
||||
for (pos = [[wall + tolerance + 2.5, wall + tolerance + 2.5],
|
||||
[wall + tolerance + pcb_w - 2.5, wall + tolerance + 2.5],
|
||||
[wall + tolerance + 2.5, wall + tolerance + pcb_h - 2.5],
|
||||
[wall + tolerance + pcb_w - 2.5, wall + tolerance + pcb_h - 2.5]]) {
|
||||
translate([pos[0], pos[1], wall])
|
||||
difference() {
|
||||
cylinder(h=post_h, d=post_d, $fn=20);
|
||||
cylinder(h=post_h + 1, d=screw_d, $fn=20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Lid (snap-fit)
|
||||
// ============================================
|
||||
module lid() {
|
||||
difference() {
|
||||
union() {
|
||||
// Lid plate
|
||||
rounded_box(outer_w, outer_h, wall, 3);
|
||||
|
||||
// Inner lip for alignment
|
||||
translate([wall - lid_lip/2, wall - lid_lip/2, wall])
|
||||
rounded_box(inner_w + lid_lip, inner_h + lid_lip, 2, 2);
|
||||
}
|
||||
|
||||
// Status LED window (small hole)
|
||||
translate([wall + tolerance + 40, wall + tolerance + 25, -1])
|
||||
cylinder(h=wall+2, d=2, $fn=16);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Helper modules
|
||||
// ============================================
|
||||
module rounded_box(w, h, d, r) {
|
||||
hull() {
|
||||
translate([r, r, 0]) cylinder(h=d, r=r, $fn=20);
|
||||
translate([w-r, r, 0]) cylinder(h=d, r=r, $fn=20);
|
||||
translate([r, h-r, 0]) cylinder(h=d, r=r, $fn=20);
|
||||
translate([w-r, h-r, 0]) cylinder(h=d, r=r, $fn=20);
|
||||
}
|
||||
}
|
||||
|
||||
module wall_mount_keyhole() {
|
||||
// Large hole (screw head)
|
||||
cylinder(h=wall+2, d=7, $fn=24);
|
||||
// Slot (slide down to lock)
|
||||
translate([0, -5, 0])
|
||||
hull() {
|
||||
cylinder(h=wall+2, d=4, $fn=24);
|
||||
translate([0, 5, 0]) cylinder(h=wall+2, d=4, $fn=24);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Render
|
||||
// ============================================
|
||||
|
||||
// Body
|
||||
body();
|
||||
|
||||
// Lid (offset for viewing - move to origin for printing)
|
||||
translate([outer_w + 10, 0, 0])
|
||||
lid();
|
||||
1766
enclosure/lid.stl
Normal file
1766
enclosure/lid.stl
Normal file
File diff suppressed because it is too large
Load Diff
2
enclosure/lid_only.scad
Normal file
2
enclosure/lid_only.scad
Normal file
@@ -0,0 +1,2 @@
|
||||
use <enclosure.scad>;
|
||||
lid();
|
||||
Reference in New Issue
Block a user