Skip to content

DJM0/LoadShed

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LoadShed

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.

PCB render

Demo: test mode PWM wave

Why this exists

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 limitations).

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.

Installed alongside a Victron MPPT and inverter

What it does

  • 4 output channels (low-side N-MOSFET switching from a regulated 12 V rail), each channel independently configured as one of three modes:
    • Dimmable: front-panel pot sets brightness, 0–100 % PWM
    • On/off: full-power switching (pumps, external relay modules)
    • Temperature-controlled: thermostat relay with hysteresis, or proportional PWM ramp (fans, heaters) driven by the onboard SHT4x
  • 52-week scheduling: on/off rules per channel as fixed local times or sunrise/sunset ± offset, computed per ISO week from your coordinates, plus an optional "safety off" backstop time that always wins
  • Battery protection: global low-voltage disconnect with hysteresis, and per-channel linear derating that dims loads as the battery sags instead of hard-cutting them. Each channel also has its own minimum start voltage, so schedules skip low-priority loads when the battery can't spare them
  • Thermal protection: over-temperature shutdown using both the SHT4x and the MCU's internal sensor, with hysteresis and a settling countdown on recovery
  • Local UI: 128×32 OLED with live status, per-channel detail views, fault screens, a button menu (time set, test mode, schedule toggle, limits view), 4 buttons and 4 pots
  • Timekeeping: DS3231M temperature-compensated RTC with CR2032 backup; the MCU runs in UTC and shows UK local time (GMT/BST) on the display

The hardware

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.

Getting a board

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.

The board on the test bench

⚠️ Electrical warnings: read before wiring

  • Inductive loads need a flyback diode. The MOSFETs have no on-board clamping. If you connect anything with a coil (pump, brushed motor, fan, solenoid), fit a flyback diode (e.g. 1N5819/SS34) across the load, at the load end, cathode to +12 V. PWM-switching an unclamped inductive load will kill the MOSFET.
  • Relays count as inductive loads. If you drive an external relay or relay module from a channel, the relay coil needs the same flyback diode across it (many relay modules include one; bare relays don't).
  • Outputs are low-side switched. Each channel switches the load's negative return; +12 V is always present at the output terminal. Loads must be floating. Don't tie the load's negative to battery negative or chassis, or the channel can never turn off.
  • Respect the rail budget. All four channels share the 12 V 3.5 A rail. Per-channel polyfuses are 3 A, but they protect the traces, not your load.
  • This is not a BMS. The low-voltage disconnect and derating protect your battery from these loads only. Use a proper BMS/LVD for the bank itself.
  • 12–32 V DC only. Nothing about this design is mains-rated.

Limitations & scope

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):

  • All four channels are MOSFET/PWM, with no dry-contact relay outputs. In hindsight one or two relay channels would have been worth the board space.
  • No on-board flyback/TVS clamping and modest SOT-23 MOSFETs: fine for LED lighting and small pumps/fans, not for big or badly-behaved loads.
  • Battery sensing is sized for 12 V banks (see note above).
  • No reverse-polarity protection. The fuse covers overcurrent only; you are expected to connect the battery the right way round. Reverse protection is something a future revision could look at, but it hasn't been investigated.

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):

  • Reconfiguring requires a computer: schedules and thresholds are compiled into flash, so changes mean regenerate then reflash over UPDI. On-device configuration (EEPROM-stored schedules, editable over serial) is the single biggest improvement someone could contribute.
  • It was never power-optimised. The firmware polls in a busy loop. A proper low-power rework (sleep modes, the RTC's alarm output as a wake interrupt, shedding the Arduino layer) could cut idle draw dramatically. My system grew big enough that I stopped caring, but for a truly tiny panel/battery this is the contribution to make.
  • UK-only daylight-saving rules: schedule times are baked to UTC and the display computes GMT/BST. Anywhere on UTC works as-is; a configurable timezone/DST rule is the other big contribution candidate.
  • Protection checks pause inside the (blocking) menu and test mode.
  • One rule set per ISO week; no per-day-of-week schedules.
  • The config tool is macOS/Linux only (Unix pty); Windows users need WSL.
  • No logging, so it can't tell you what happened last Tuesday.

How you configure it

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.

Repository layout

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

Licences

  • Firmware, tools, scripts, docs: MIT
  • Hardware (everything under hardware/): CERN-OHL-P v2 (permissive)

Note the imported JLC/LCSC component libraries are not redistributed here; see hardware/README.md.

About

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.

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Contributors