Give an old solar panel a second life.
A raised garden bed whose canopy is a working solar panel β the same square foot grows tomatoes and generates electricity. Symbiosis of energy production and agriculture: the plants get filtered afternoon shade where they need it most; the panel keeps generating on a structure that would have been lumber anyway.
Open-source end-to-end: 3D model, sun simulation, wind-load analysis, cut lists, schematic (rev B), ESPHome firmware (v3.2), PCB layout, and a GitHub Pages site. MIT license, no paywalls, no telemetry.
Status: working prototype. The Mini v2.4 is built and running on the bench. The full-size build (Longi 620W) is mechanically and aerodynamically validated by FreeCAD 3D model + ASCE 7-22 wind calc + geometric shadow raycaster. Firmware v3.2 is compiled and ready to flash (the chip is currently wedged; see Status & roadmap below).
Live site: mokahlo.github.io/wattplot Β· 3D booth viewer: mokahlo.github.io/wattplot/booth/ Β· Data dashboard: mokahlo.github.io/wattplot/data.html
Same bed, same 72" corner posts, same panel rails β pick your tilt mechanism:
| Basic | Smart | |
|---|---|---|
| Tilt | Fixed, pinned prop strut (0/15/25/35Β°) | Motorized, 0β35Β°, linear actuator |
| Electronics | None | ESP32 controller + sensors + PCB |
| Storm response | Manual stow: pull pin, lay flat (2 min) | Auto-fold on wind, plus manual stow |
| Panel | Salvaged/upcycled panel ideal | New 620 W bifacial (or any preset) |
| Cost | ~$400β650 (salvage panel, incl. soil) | ~$1,600 |
| Time | A weekend | 10β15 hr + electronics |
| Guide | docs/build_basic.md |
docs/build_guide.md |
Start with Basic. It's the whole idea in its cheapest form: a raised bed that shades its crop and pays you back in watts, built with a drill and a saw. Smart is the flagship upgrade β every Basic build has the strut holes and pivot line to accept the actuator later.
| Layer | State | Notes |
|---|---|---|
| 3D model | β Validated | FreeCAD assembly, STEP+STL+FCStd export. 5 panel presets. |
| Sun simulation | β Validated | analysis/sun_simulator.py β annual kWh, daily DLI, tomato yield. |
| Wind load | β Validated | ASCE 7-22, Cat II 700-yr, Exp C, Phoenix. |
| Cut lists | β Validated | models/cut_list.py β every board, every cut. |
| Mini v2.4 (electronics) | β Built & running on bench | 18Γ14β³, 10W panel, kickstand actuator, ESPHome firmware. |
| Full-size structural (Basic) | β Designed | 8Γ5 ft bed, no electronics. Weekend build. |
| Full-size Smart (electronics) | π‘ Firmware ready, chip wedged | Schematic rev B + firmware v3.2 compiled; needs physical BOOT+RESET. |
| Custom PCB | β Designed | Schematic + PCB layout. JLCPCB-ready. |
| GitHub Pages site | β Live | Dark theme, 10+ pages, 3D viewer, data dashboard, gallery, diagrams. |
| Booth materials | π‘ Mid-refresh | One-pager + FAQ + poster + sim ready; needs new symbiosis framing. |
| Trademark (WattPlot name) | π‘ Coexistence request drafted | docs/_internal/COEXISTENCE_REQUEST.md. Awaiting Andrew Welch's reply. |
What this means in practice: the design is complete, the documentation is live, the firmware builds clean. The two remaining "blocked" items are (1) recovering the wedged ESP32-S3 so we can flash v3.2, and (2) hearing back from the WattPlot.com operator on whether coexistence on the name is OK.
Three constraints guide every part of the design:
- No miter cuts. Every cut is a 90Β° square cut. Joints are butt, half-lap, or lap. (You don't need a miter saw.) Caveat: post lateral bracing is still unresolved precisely because the conventional answer needs miters - see "Open structural questions" below.
- All hardware off the shelf. Hinges, panel clamps, bolts, screws, rod, and pins are standard sizes from Home Depot, McMaster, or solar-mounting suppliers (IronRidge / Unirac / Quick Mount). No custom metal parts.
- Simple, common dimensions. All lumber from standard stock lengths (8 ft, 10 ft, 12 ft) with reasonable waste. No fractional-inch stock lengths. 96" panel rails (2x6x8ft, no waste), 72" corner posts (4x4x8ft, 24" waste), 89"/37.6" wall skin between the posts (1x6x8ft cedar).
Open the 3D viewer - drag to orbit, scroll to zoom. Loads the live STEP-derived STL.
Sept 25-27, 2026 Β· Mare Island Naval Shipyard, Vallejo CA.
A working Mini v2.4 on the table, 24" live-sim dashboard next to it,
printed poster, take-home cut-list cards. The booth package
(booth plan, demo script, FAQ, parts list, interactive viewer, sim
dashboard) lives in booth/.
If you're at the faire, come by. If you want to exhibit your own agrivoltaic / solar / smart-garden project, the booth package documents what worked (and what to skip) for next time.
A single Wattplot planter is bounded by 8-ft lumber stock: 8 ft long, 5 ft wide. The bed is sized to the panel (with up to 0.5" overhang per side), and the cut list is derived from the bed.
A Wattplot is, at heart, an example of symbiosis between energy production and agriculture: the same square foot grows tomatoes and generates electricity, because the panel that shades the crop is the panel that powers the irrigation. The structure would be lumber either way; the panel is what turns a planter into a power plant.
A natural fit is to use decommissioned rooftop panels that would otherwise be landfilled β a 12-year-old 250 W residential panel is still a 235 W panel, perfectly useful for shade plus some power, and you delay recycling by 10β20 years. The design supports both new and salvaged panels; "bring your own."
Five validated panel presets are in wattplot_params.py:
| Preset | L Γ W (in) | New W | Derated W |
|---|---|---|---|
longi_620W (new bifacial) |
97.0 Γ 44.6 | 620 W | 620 W |
residential_60cell |
65.0 Γ 39.0 | 250 W | 235 W (12 yr) |
residential_72cell |
77.0 Γ 39.0 | 300 W | 288 W (8 yr) |
commercial_96cell |
65.0 Γ 41.0 | 400 W | 388 W (6 yr) |
large_format_1m65 |
65.0 Γ 41.0 | 400 W | 392 W (4 yr) |
import wattplot_params as P
P.apply_panel_preset('residential_60cell') # bed resizes automaticallyFor custom panels, set PANEL['L_in'], PANEL['W_in'], wattage,
panel_age_years, panel_bifacial, and the bed + derated wattage
are computed for you. See docs/upcycling.md
for the full guide (lumber math, MPPT sizing, when a salvage
panel is not a good fit).
The Mini v2.4 build is on the bench (see Status table). Photos of the full-size
build will go in renders/build_photos/ once the full-size prototype exists;
until then, the booth package in booth/ has the wood-frame renders
that represent the as-designed geometry. The template below describes the
shot list once a physical build is in hand.
Build the entire apparatus: see docs/build_guide.md for
the step-by-step assembly guide (8 phases, ~10-15 hours). (Note: this doc is
written for the v2 architecture; treat it as design intent and cross-check
against firmware/wattplot.yaml for the current pin map and entity names.)
Test & validation: see docs/test_checklist.md for
per-component and per-system tests, with a final sign-off checklist. (Same
staleness caveat as build_guide.md.)
Photo template (for the build log):
| # | Subject | Angle | Notes |
|---|---|---|---|
| 1 | Overview of completed build | Iso from southeast, 20Β° elevation | Frame at 35Β° tilt, full bed |
| 2 | Bed close-up | Front (south wall) | Show 1x6 skin over 2x4 cleats, 2x4 header |
| 3 | Post-to-rail joint | Iso from north | Show 4x4 post top + 2x6 rails |
| 4 | Hinge detail | Side, 12" away | One hinge in close-up, show leaf + knuckle + 1β2" pin |
| 5 | Actuator mount | Side | 2x6 PT clevis on north rail, 2x6 wall block, 1β2" pin |
| 6 | Panel mounting | Above, looking down | 6Γ aluminum mid-clamps on the rails |
| 7 | PCB in enclosure | Above, enclosure open | JST-XH connectors, ESP32-S3, DRV8871s, INA219s visible |
| 8 | Wiring close-up | Side, 6" away | Cable carrier with motor + actuator leads |
| 9 | Soil sensors | Soil cross-section | DS18B20 + soil moisture in the bed |
| 10 | Soil filled + planted | Front | 4 tomato seedlings, 11.25" soil depth |
| 11 | Dashboard on phone | Phone in hand | HA dashboard showing tilt, motor current, panel power |
| 12 | Canopy at 35Β° (max tilt) | Iso from east | Power mode, structural max |
| 13 | Canopy flat (storm) | Iso from east | Folding mode, stowed |
Add your photos to renders/build_photos/ and link them in this section.
wattplot.py β top-level pipeline: python wattplot.py
wattplot_params.py β single source of truth for ALL parameters
models/
freecad/ β FreeCAD parametric 3D model
materials.py β wood species, fasteners, hardware
parts/ β one file per part (bed_wall, frame,
_helpers.py, bed_wall.py, β hinge, panel_clamp, actuator_mount,
frame.py, panel.py, hinge.py, β skids, diagonal_brace, ...)
panel_clamp.py, skid.py,
actuator_mount.py
assemble.py β imports all parts, exports STEP+STL+FCStd
_run.py β freecadcmd entry point
shadow_raycaster.py β geometric bed-shadow from 3D panel
render_3d_views.py, render_svg_views.py
analysis/
sun_simulator.py β annual kWh, bed DLI, tomato yield
wind_load.py β ASCE 7-22 force + safety factors
engineering_drawing.py β side-view engineering drawings
pcb_schematic.py β PCB block-diagram generator
renders/ β generated PNGs (mostly gitignored)
firmware/ β ESPHome firmware for the controller
docs/ β design + build + test docs (see below)
index.html β GitHub Pages 3D viewer
control_law.md β firmware spec (state machine, PI loop)
pcb_design.md β custom PCB spec (KiCad-ready)
wiring.md β pin-by-pin wiring from PCB to apparatus
sensor_placement.md β where each sensor mounts + why
build_basic.md β Basic tier: fixed pinned tilt, no electronics
build_guide.md β step-by-step build (8 phases, ~10-15 hours)
test_checklist.md β per-component + integration tests
watering.md β smart planter: sensors + solenoid + automation
logging.md β v2.5: MQTT log streaming to wattplot.log
All design rules, the build, the wiring, and the tests are documented.
wattplot_params.py is the single source of truth - change a value there
and the whole pipeline (3D model, shadow, sun sim, wind sim) updates in
~10 seconds.
An 8 ft Γ 3.7 ft planter with 27.5" walls (29" rim height β top of the wheelchair-accessible seated-gardening range, with access from both long sides) holding 25.5" of soil, carrying a solar panel on four 72" 4x4 corner posts (walk-under canopy). The panel sits on 2x6 rails laid across the post tops and tilts about its long axis. The bed is the ballast - no ground anchors. In the Basic build the panel rests on a pinned 2x4 prop strut (fixed tilt, set by hand). In the Smart build it's driven by a linear actuator (0-35Β°; storm fold = flat), and the controller uses a PI loop on motor current to reduce tilt under wind load, then returns to the commanded angle when wind drops.
35Β° is the structural max, and the post height is why. Raising the canopy to 6 ft puts panel drag on a ~6 ft lever arm about the bed edge - roughly 3Γ the moment of a bed-level panel. At 35Β° the structure holds SF 2.55 against overturning; 45Β° drops to 1.89 and 90Β° to 1.26, both below the 2.0 target. The old 90Β° "sun-on-bed / wring-out" modes are retired - to give the bed full sun, stow the panel flat instead.
Frame material: all lumber for sustainability (FSC Douglas Fir where available). Hardware (hinges, panel clamps) is metal where the load demands.
βββββββββββββββββββ
β 620W bifacial β
β main panel β β the only solar source
ββββββ¬βββββββββββββ
β DC bus (30-40V, 0-18A)
ββββββββββ΄βββββββββ
β β
βΌ βΌ
ββββββββββββ βββββββββββββββββββββ
β Micro- β β MPPT (Victron β
β inverter β β 100/30 or EPEver β
β (AC out) β β Tracer 4210AN) β
ββββββ¬ββββββ ββββββββββ¬βββββββββββ
β β
βΌ βΌ
[240V AC] ββββββββββββ
β 12V β β the only battery
β LiFePO4 β
ββββββ¬ββββββ
β
βΌ
ββββββββββββββββ
β ESP32 + β
β DRV8871 ββββΊ Linear actuator (panel tilt)
β BMI160 IMU β β closed-loop position
β INA219 β β actual tilt
β DS18B20 β β
β soil sensor β
ββββββββββββββββ
Only two energy sources: the main 620W panel and the 12V battery. No separate trickle panel. The main panel feeds both the microinverter (for AC) and a real hardware MPPT (Victron SmartSolar 100/30 or EPEver Tracer 4210AN) for 12V battery charging - both from the same panel via a Y-splitter on the MC4 leads. The 620W panel produces 50-100Γ more energy than the controller needs, so it's a non-issue.
Earlier revisions (v2.0-2.3) used a DPS5005 programmable buck + UART-MPPT pattern for the full-size build. That was retired: the DPS5005 was a hack (using a bench PSU as a charge controller) and was also undersized for the 620W panel (5A max output would have thrown away ~90% of the panel's potential). The mini build (v2.4) uses a standalone Sunapex 10A MPPT - no host connection, IP67 waterproof, LiFePO4-aware out of the box. The full-size build needs the larger Victron/EPEver above. See
docs/build_guide.mdΒ§7.
- Wind: 115 mph 3-sec gust design. At 25.5" soil fill (~4,800 lb dead load in the 27.5"-wall bed), the structure passes safety factor β₯ 2.0 from 0-35Β° tilt β 35Β° is the max operating angle, set by the 72" post height. Rated deployed wind: ~130 mph at 35Β°. Stowed flat (0Β°) the panel carries no drag or uplift and only the posts are loaded (SF 26.8); stow is the storm answer for both tiers (manual pin on Basic, auto-fold on Smart). The bed depth is set by dry-soil risk: at 4 wall courses a bone-dry bed falls to SF 1.53, so the build ships 5 courses.
- Power (azimuth tracking 35Β° tilt, Phoenix 2025): 2,240 kWh/year.
- Tomato yield (35Β° tilt): ~124 kg/year from 4 plants. Vertical (90Β°) gives full bed sun but ~50% less power and more heat stress.
- Best balance: static 35Β° or azimuth tracking 35Β°, depending on whether you value simplicity or kWh.
See analysis/wind_load_report.md and analysis/sun_simulator.py for the
underlying calculations.
Raising the canopy onto 72" posts solved the walk-under/reach-under problem but opened two checks. Both are now analyzed β and the first one fails as currently specced:
- Post bending.
analysis/post_bending.pychecks the 4x4 posts as cantilevers carrying panel drag at their base connection (the wind analysis inanalysis/wind_load.pyonly checks the structure tipping as a rigid body β a separate failure mode). Result: FAIL at the 35Β° operating cap (SF 0.65 vs. target 1.5, worst-case load sharing). Unbraced, the real bending-safe tilt limit is closer to 20Β° than 35Β°. Two remedies, either sufficient: (A) upsize to 6x6 posts (SF 2.53, passes with margin) or (B) add lateral bracing (below) and confirm the residual base moment fits a standard bracket. Seeanalysis/post_bending_report.mdfor the full numbers. - Lateral bracing. A 6-ft post-and-beam frame needs diagonal
bracing. The retired panel-frame diagonal doesn't apply here, and the
obvious knee brace wants 45Β° miters, which collides with design rule
#1 (no miter cuts). Square-cut gusset plates are the answer β a
square-cut brace (or a plywood/steel gusset alone) bolted flat across
the post/rail corner carries the same axial force a mitered brace
would, with zero non-90Β° cuts. Sized in
analysis/post_bending.py(Β§Bracing): ~335 lb axial demand at the 35Β° cap, spec target β₯ 500 lb β well within off-the-shelf structural angle brackets.
Do not build the full-size Smart tier with 4x4 posts, unbraced, at 35Β° tilt until one of the two remedies above is locked in. Both are tracked before any full-size build; this is a first-pass calc, not a stamped one β get a PE review before anything goes in the ground.
Every priority is clamped to ΞΈ_max = 35Β° (the structural cap β see
docs/control_law.md). The old 90Β° "wring-out"
and "bed-sun" modes are retired: to give the bed full sun or dry it out,
stow flat at 0Β° instead, where the panel shades nothing and carries
~zero wind load.
priority source sets ΞΈ_desired / lights
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1 user override arbitrary 0-35
2 hard current limit ΞΈ = 0 (safety)
3 NWS rain forecast + dry soil ΞΈ = 0 (capture rain)
4 NWS wind forecast > 50 mph ΞΈ = 15 (preemptive)
5 wind β₯ 50% of I_safe pause tracking
6 soil wet 72h+ ΞΈ = 0 (stow flat, sun dries bed)
7 soil dry 48h+ + no rain β conserve ΞΈ = 35
8 time-of-day + tracking mode ΞΈ = 0-35 (azimuth track, capped)
L1 battery SOC < 50% lights off
L2 natural DLI > target lights off
L3 DLI deficit > 0 (need light) lights on (pre/post-dawn)
L4 hard constraint 8 hr dark minimum
Goal: keep motor current below I_safe, while maximizing commanded tilt for sun exposure.
docs/control_law.md is the canonical version of this table; the firmware
enforces the 35Β° cap in the commanded_tilt number component.
# Full pipeline (3D model export + sun sim + wind sim)
python wattplot.py
# Just the simulation (skip the 3D export)
python wattplot.py --skip-model
# Just one analysis
python analysis/sun_simulator.py
python analysis/wind_load.py
# Override a parameter at the command line
python wattplot.py --tilt 50
# View the 3D model in a browser
open renders/viewer.html- Python 3.10+
numpy,pandas,matplotlib,pvlib,shapely,scipy(for analysis)- FreeCAD 1.0+ (for the 3D model -
freecadcmdis auto-detected on Windows inC:\Program Files\FreeCAD *\bin\) ruff(for lint)
pip install numpy pandas matplotlib pvlib shapely scipy ruffThe 3D model is built by FreeCAD. On Windows with FreeCAD 1.0+ installed
in the default location, the orchestrator finds it automatically. To
override, set $FREECADCMD to the path of freecadcmd.exe.
This is the full flagship BOM. Basic tier deletes the actuator,
MPPT-for-controller, LiFePO4, ESP32/PCB, and grow light rows, and swaps
the new 620W panel for a salvaged one β see
docs/build_basic.md.
| Component | Spec | ~$ |
|---|---|---|
| Bed walls | 1x6 cedar skin (5 courses, 27.5" tall) + 2x4 PT cleats + 2x4 headers; 29" accessible rim | 185 |
| Corner posts | 4 Γ 4x4 PT, 72" (walk-under canopy support) | 60 |
| Panel rails | 4 Γ 2x6 cedar, laid flat across the post tops | 45 |
| Soil | 25.5" fill β 2.2 cu yd β 4,500 lb (the ballast) | 160 |
| Frame rails | 2x6 PT DF, 2 Γ 8 ft long + 2 Γ 8 ft cross | 60 |
| Diagonal brace | 2x4 PT DF, 1 Γ 10 ft | 15 |
| Skids | 4x4 PT DF, 2 Γ 8 ft | 30 |
| Hinges | 4 Γ galvanized butt hinges 4"Γ4", 1β2" pin, +96" 1β2" rod | 35 |
| Panel clamps | 6 Γ aluminum mid-clamps, 35mm channel | 18 |
| Linear actuator | 12V, 4" stroke, IP65, 330 lb | 60 |
| MPPT charge controller (full-size) | Victron SmartSolar 100/30 (30A, 100V) or EPEver Tracer 4210AN (40A, 100V) | 200 |
| Panel | 620W bifacial (LONGi Hi-MO X10 or similar) | 200 |
| Microinverter | Enphase IQ7+ or APsystems DS3, 240V, UL 1741 | 150 |
| 12V 100Ah LiFePO4 | LiTime or similar | 230 |
| ESP32 + custom PCB | w/ DRV8871, INA219, BMI160, sensors | 120 |
| 200W LED grow light | full spectrum, IP65 (v2) | 130 |
| Misc (screws, bolts, wire, irrigation) | 50 | |
| Total parts | ~$1,400 |
All structural lumber is FSC Douglas Fir where available. No welding. No
concrete. See bom.md for sourcing notes.
The MPPT is a real hardware charge controller (Victron or EPEver) sized for the 620W panel - no firmware-side MPPT loop, no UART setpoint commands. ESP32 reads MPPT telemetry (panel V/I, battery V, charge state) over VE.Direct / RS-485 for energy monitoring and Home Assistant visibility. The same panel also feeds the microinverter for AC output via a Y-splitter. No separate trickle panel needed.
- Parametric 3D model (FreeCAD) with STEP / STL / FCStd export, one
file per part (
models/freecad/parts/) - All-wood perimeter frame design (2x6 rails + 2x4 brace, half-lap bed corners)
- ASCE 7-22 wind load analysis, Phoenix, Exp C, Cat II 700-yr
- Geometric shadow raycaster (uses actual 3D panel)
- Annual sun + yield simulator (5 tilt schedules, Phoenix weather)
- Engineering side-view drawings (with frame + actuator + hinge detail)
- PCB spec (KiCad-ready) -
docs/pcb_design.md - Wiring diagram (pin-by-pin) -
docs/wiring.md - Sensor placement plan -
docs/sensor_placement.md - Build guide (8 phases, ~10-15 hours) -
docs/build_guide.md - Test & validation checklist -
docs/test_checklist.md - ESPHome firmware (PI controller, NWS polling, fold logic) -
firmware/ - Order custom PCB from JLCPCB
- Real-world deployment validation
Wattplot builds on the work of many open-source projects. If you find their work useful, please support them.
- NREL/bifacial_radiance - gold-standard bifacial PV ray-tracer. Our 2D
shadow_raycaster.pyis a simplified version of what bifacial_radiance does in 3D. - NREL/InSPIRE - agrivoltaic tutorials, scripts, and research workflows.
- DailyAgrivoltaicOperation (astuhlmacher) - dual-axis panel optimization under crop constraints, the academic version of what Wattplot does in firmware.
- PASE 1.0 - Python Agrivoltaic Simulation Environment, energy + crop dual-objective.
- Helioduino (NachtRaveVL) - mature LDR-based sun tracker for Arduino. The reference for "professional grade" tracker control.
- SolarArduino (HDwayne) - ESP32 sun tracker with wind safety using an anemometer (folds to safety position for 15 min if wind > 5 m/s). The pattern for our wind-safety state machine in
docs/control_law.mdcomes from here. - Sunchronizer (Nerdiyde) - ESP32 + 6000N linear actuator + BMI160 IMU for closed-loop position feedback. We adopted the IMU approach for the same reason (drift-free actual tilt angle).
- f2knpw/ESP32_Solar_Tracker - Lite ESP32 solar tracker with sun-position calc, sleep mode, OTA.
- Earlier revisions of Wattplot (v2.0-2.3) used a DPS5005-as-MPPT pattern (similar to OSPController and fugu-mppt-firmware below). This was retired in v2.4 because the DPS5005 was both a hack (using a bench PSU as a charge controller) and undersized for the 620W panel. The current build uses off-the-shelf hardware MPPTs (Sunapex HC-SM10A on the mini, Victron/EPEver on the full-size) - the firmware no longer commands a charge controller, it only reads telemetry.
- OSPController (Open Solar Project) - ESP32 controls a commercial DPS5005 buck via UART for MPPT. Good reference if you want to revive the UART-MPPT pattern (e.g., to add telemetry from a Victron VE.Direct port to a custom control loop).
- fugu-mppt-firmware (fl4p) - ESP32 MPPT firmware, 95% efficient synchronous buck. Reference for designing a custom MPPT from scratch (we deliberately chose not to).
- akgang ESP32 MPPT - single-file Arduino ESP32 MPPT with INA226, web dashboard, NASA POWER + OWM forecasts. Reference for the MPPT loop algorithm (perturb-and-observe with dither) if we ever need to bring back a firmware-side MPPT step.
- SolarWS (BeardedTinker) - ESPHome weather station, deep sleep at night, OTA.
- solar_weather (squidpickles) - ESPHome config for solar weather station.
- Home Assistant Forecast.Solar integration - built-in solar production forecast for HA. A drop-in alternative to our NWS-based forecast.
- POSCAS - Parametric Open Source Cold-Frame Agrivoltaic System. The closest analog to Wattplot in philosophy (open-source, parametric, agrivoltaic) but for a cold frame. Worth studying.
- Vege Garden Automation (Rototron) - solar-powered soil sensors + MQTT + HA on a raised bed. Validates the IoT + raised bed + solar pattern Wattplot uses.
- ASCE 7-22 - wind load provisions. Our
analysis/wind_load.pyuses ASCE 7-22 Table 26.10-1 for velocity pressure exposure coefficients. - pvlib - solar position + clear-sky modeling. Industry standard, NREL-developed.
- IEC 61215 / UL 61730 - panel safety standards. Our 620W bifacial panel is certified to these.
- UL 1741 / IEEE 1547 - grid-tie inverter safety. We use a commercial microinverter (Enphase IQ7+, APsystems DS3) that meets these, so the user doesn't have to.
- Utah SB 190 (2024) - first comprehensive balcony solar law, 800W plug-in allowance.
- California AB 1076 (2022) - most generous, 5 kW plug-in allowance.
- Colorado HB 22-1015 (2022) - 800W plug-in, similar to Utah.
Wattplot's 620W panel is below the 800W threshold in Utah and Colorado, and well within California's 5 kW cap. Design fits the regulatory window for plug-and-play solar in all three states.
- cadquery - parametric 3D model
- shapely - 2D geometry for the shadow raycaster
- cairosvg - SVG β PNG rendering
- matplotlib - plots
- three.js - the interactive 3D viewer in
docs/
This project is licensed under the MIT License - see LICENSE.
You are free to use, modify, and sell products based on this design. Attribution appreciated.
Issues, PRs, and forks welcome. The system is small enough that you should be able to read the whole codebase in an afternoon.
If you build one, send photos.
pvlib(Sandia / pvlib-team) for solar position + clear-sky modelingcadqueryfor parametric CADshapelyfor 2D geometry- ASCE 7-22 for the wind provisions
- The "balcony solar" laws in Utah (SB 190), California (AB 1076), and Colorado (HB22-1015) for inspiring the plug-and-play direction