Loading 3D model… large boards can take a moment.
Off-grid 4-channel PWM load controller with regulated 12 V output from any 12–32 V battery. Sunrise/sunset + RTC scheduling, LiFePO₄ battery protection, dimming pots and an OLED. ATtiny3216 firmware + KiCad hardware. No WiFi, no cloud, no app.
I was planning a small 12 V off-grid solar system for the shed at the end of my garden, too far from mains power and too far from the house for WiFi. Initially all I wanted to run was a pond pump and some festoon lights.
When I started researching controllers, the majority were relay-based, with no dimming. 12 V outdoor lighting is becoming more popular, and I had a cheap set of festoons that worked great, but with the included mains-to-12 V supply they couldn't be dimmed, and I always thought they were too bright. Testing PWM on them worked really well; mine now run at about 20 %.
The other gap: none of the MOSFET controllers I found gave you a regulated supply. Lights like mine are rated for 12 V and nothing more. There's no regulator after the plug-in supply; it drives the bulbs directly. Yet on a battery system you're expected to hang them straight off a LiFePO₄ bank that sits anywhere up to ~14.6 V on charge. Automotive-grade 12 V kit is designed to tolerate that, but a lot of "12 V" equipment isn't. On this board the loads run from a proper regulated 12 V rail, so nothing ever sees more than 12 V, and lights don't flicker or shift brightness as the battery works.
Efficiency mattered too, in two ways. The original plan was a single 100 W panel getting through a British winter, so I wanted the MCU to be as efficient as possible. That ruled out ESP32-class boards, and since there's no network in the shed I didn't need their networking or Home Assistant anyway; an Arduino-style ATtiny was the more suitable choice. The second half is the scheduling itself: not just "on at nightfall" or a fixed timer, but proper sunrise/sunset awareness for every week of the year. Combining sunset triggers with fixed cut-off times also meant the festoons wouldn't annoy the neighbours by burning all night, and that combination gave me far more flexibility than any of the dusk-sensor or plug-in timers on the market. All the heavy logic (sun times for 52 weeks, DST conversion) runs in a browser tool on a computer; the ATtiny just gets a precomputed table and works entirely offline.
In the end I over-built the system: a 500 W bifacial panel and a 205 Ah LiFePO₄ battery, totally unnecessary for my loads, but I did it because I could. So I never did the aggressive power optimisation I'd planned, and the firmware polls in a loop rather than sleeping on RTC interrupts (see ).
What it does do is watch the battery and shed load, dimming first, then disconnecting, before a dark week can drag the bank down. And it's smarter than a blunt cut-off: the scheduler checks the battery against each channel's own minimum voltage before deciding whether a load is even worth running. In my setup the pump simply doesn't bother turning on when the battery is low, so the festoon lights get priority instead. Hence the name.
The onboard temperature sensor does double duty. A thermostat mode runs the extractor fan in my shed automatically, and the same sensor provides an over-temperature shutoff for all the loads when the shed gets too hot.
KiCad 9 project in hardware/, with a
schematic PDF, gerbers, BOM and placement
files for JLCPCB assembly in hardware/production/.
Full fabrication notes in hardware/README.md.
| MCU | ATtiny3216 @ 20 MHz internal, programmed via UPDI |
| Input | 12–32 V DC, master fuse + power switch (32 V limit set by the 3.3 V regulator) |
| Load rail | Regulated 12 V @ 3.5 A (AP64502 buck), so loads get a stable 12 V regardless of battery state |
| Logic rail | 3.3 V @ 2 A (AP63203 buck) |
| Outputs | 4 × AO3400A N-MOSFET low-side switches, 3 A self-resetting polyfuse per channel |
| RTC | DS3231M (±5 ppm) with CR2032 backup |
| Sensor | SHT4x temperature / humidity |
| Display | 0.91″ 128×32 SSD1306 OLED (I2C) |
| Controls | 4 push buttons, 4 potentiometers |
| Spare | PB3 broken out to a header |
Note on 24 V banks: the regulators are happy up to 32 V in, but the battery-sense divider is sized for 12 V systems (full scale ≈ 15.5 V), so the battery-protection features only work meaningfully on a 12 V bank as built. Running at 24 V means changing two divider resistors and checking indicator-LED dissipation; see the hardware README.
The v1.2 run was fabricated by JLCPCB, with economic assembly placing all of the SMD parts. What arrives needs only the through-hole bits hand-soldered: screw terminals, buttons, pots, headers, power switch and the OLED. Nothing fine-pitch; easy work with any iron. What it actually cost (2026):
| Item | Qty | Cost |
|---|---|---|
| Bare PCBs | 5 | $9.50 |
| Economic assembly (all SMT parts included) | 2 boards | $83.48 |
(Those are referral links; they knock a few dollars off your first order and cost you nothing.)
Don't want to order and solder? I have spare boards from the run and am happy to do small batches. Open a GitHub issue or email hello@davidmaitland.me and I'll quote a bare or assembled board at cost plus shipping.
Scope, first. The ATtiny was a deliberate choice: the whole controller is lightweight, cheap, low-quiescent and easy to fabricate, with nothing to update and nothing to pair. The flip side is that this project will never grow WiFi, Home Assistant integration, MQTT, or a web dashboard, the features most modern projects strive for. If you want those, you want an ESP32-class platform, and building one is out of scope here. LoadShed is for systems that should keep working when everything else is off.
Hardware considerations (a respin could fix these; PRs and forks welcome):
That said, the hardware currently fits all of my needs, and the first revision worked well enough that I never needed a second spin. If I ever did a v2, I'd definitely consider a couple of relay channels and more built-in protection, and I'd look at more flexibility in what the MOSFETs switch: selectable supplies behind them, so a channel could carry unregulated battery voltage, or more regulation options across the board so you could route 5 V to an output if you wanted. (No idea yet how I'd do that cleanly.) Possibly even a more capable microcontroller with wireless connectivity to suit other applications, though for my shed that was always out of scope.
Firmware considerations (all fixable in software; the code is small and readable):
Honestly: with a computer. There is no on-device schedule editing (see the limitations above). What makes it liveable is the bundled web config tool:
./scripts/setup.sh # one-time: arduino-cli, megaTinyCore, libraries
./scripts/config.sh # opens http://localhost:8051
The tool is a local Flask app (nothing leaves your machine). You set your
coordinates, per-channel rules and protection thresholds in a form; it
computes sunrise/sunset for all 52 weeks with astral,
bakes local-time rules to UTC, generates the firmware tables
(schedule_data.cpp, config_generated.h), and can compile and flash the
board in one click.
Flashing uses UPDI over a cheap USB serial adapter (any megaTinyCore-supported serial-UPDI adapter, a few pounds) plugged into the 3-pin header on the board. In practice: laptop out to the shed once a season, or bring the board indoors.
./scripts/build.sh # build + flash (auto-detects the port)
./scripts/build.sh --no-flash # compile only
Firmware internals (task scheduling, module breakdown, display behaviour) are
documented in firmware/README.md.
firmware/loadshed/ ATtiny3216 Arduino sketch (megaTinyCore)
firmware/i2c-debug/ Standalone I2C scanner used during bring-up
hardware/ KiCad 9 project, schematic PDF, gerbers, BOM
config-tool/ Local Flask web UI: schedules, thresholds, flash
scripts/ setup.sh · build.sh · config.sh
docs/images/ Photos, renders, demo clips
hardware/):
CERN-OHL-P v2 (permissive)Note the imported JLC/LCSC component libraries are not redistributed
here; see
hardware/README.md.
No comments yet. Be the first to ask about this board.