This page describes a system for collecting hot water using hydronic solar panels (they circulate antifreeze and have nothing to do with the collection of electricity). Collecting heat with solar panels is several times more efficient than collecting electricity for a given size of array.
The system uses two Atmega328s programmed using the Arduino IDE to process sensor information to decide when it is appropriate to collect hot water from a rooftop hydronic (hot water) solar array. If conditions are suitable, the pump runs. If too much household hot water is collected (it rises above a temperature threshold), the solar-heated water is routed through the basement hydronic slab, which is a great heat sink even in the summer time. Other features include extensive logging (with timestamps) of data (maximums, minimums, various kinds of events). There's also some logging of information from the oil-fired boiler, which hopefully will allow me to tweak its settings for more optimized fuel savings.
I log every time the boiler turns on and the time it runs for, as well as the outdoor temperature and the fuel level. Fuel level is determined using an ultrasonic rangefinder attached to the controller's I2C bus. Since the rangefinder is 12 feet from the boiler room and at the end of a long cable (which tends to make I2C flakey), I connect that part of the I2C bus via a 4016 CMOS quad bilateral switch. This means that the only time a long cable is electrically attached to the I2C bus is when I am attempting to read the fuel level (which only happens on the hour and every time the boiler runs).
Behavior is different between season settings (winter and summer). In winter (generally four months of the year), it just circulates hot water from the panels through the basement slab, assuming the household boiler is heating hot water. In summer (generally eight months of the year), it heats water using the sun, but if the water gets too hot, it sends water through the basement slab. The system is smart enough to know that if the boiler kicks on, it's winter, and so it changes the season setting automatically. If it's above freezing at night in certain months of the year, it attempts summer mode once per night (which automatically resets to winter mode should the boiler turn on).
Here's the block diagram.
Those who are curious might want to look at an early pre-Arduino solar sufficiency controller I was using in 2005. It depended on flip flops, a ULN2003, a pair of comparators, and four potentiometers to set analog cut-on and cut-off temperature values.
Next I'll illustrate the low-tech relay-and-switch-based circuitry, which is still in use to switch 120 volt circuits and send mid-voltage signals capable of opening and closing valves. It also has rotary switches to manually select whether or not the oil burner should be a fallback heating system for the two zones (slab and hot water). "Solar Panel Water Heater Sufficiency Thermostat" is now actually controlled by the Atmega-based controller diagrammed above (from pin 14 of the Master controller). "Solar Panel Slab Sufficiency Thermostat" is also controlled by the Atmega-based controller diagrammed above (from pin 15 of the Master controller).
Here's the part of the electrical system describing how valves are opened and closed by the preceding circuit:
Here's the hydrodynamic diagram:
Here's a video of me showcasing the LCD menu system:
Controller board (this was before I added the I2C expansion buses and the quad bilateral switch), consisting of an Olimex 28-pin AVR development board and some generic expansion place (you can never have too much of that). Note the blue switch, which allows me to connect either the master or slave Atmega328 to the board's serial bus to program (or otherwise interact with) remotely. I have to use serial instead of USB to communicate with this controller because it is too far away from the computer for USB's limited range. The copper thing is a makeshift heatsink I added to the 7805 voltage regulator. Eventually I transitioned to a regulated five-volt supply, which is more energy efficient (the whole system, including LCD backlighting, uses less than a watt). The connector in the upper left corner is where I plug in a DB-25 (old-style parallel printer) port, which is how I run the various thermistor and control signals to and from my controller. Just to the right of that are two brick-red connectors. This is where I plug in resistors to form the other half of the voltage dividers that also include the thermistors. The value of the resistors should be about the same as the mid-range value of the thermistors.
Controller board's wiring. I learned long ago that strain reliefs are essential for almost every end of point-to-point wiring. You see them as little copper belt loops across the wires here and there.
Commands that can be sent to the controller via a serial terminal
? - Help
cb - Clear boiler log cursor (set it to zero).
ce - Clear extreme data (any data collected immediately afterward will be considered extreme).
cf - Clear "firing time" information for boiler.
ci - Clear forcing of solar insufficiency (forced solar insufficiency is used for debugging).
cv - Clear event log cursor (set it to zero).
d - Display byte value at the following EEPROM address of the Master (given in decimal)
db - Display the log of boiler activity.
dc - Display cursors for the logs (how far into the log they have progressed).
de - Display extremes of temperature, with dates, logged from several of the thermistors.
df - Display information about fuel use by the boiler.
dl - Display long value at the following EEPROM address of the Master (given in decimal)
dn - Display the number of seconds to be added to the real time clock weekly to minimize drifting.
dr - Display the values of a number of important realtime variables.
ds - Display logs of 80 most recent morning beginnings of solar heat collection.
dt - Display the count of the number of times the boiler has fired for this tank of fuel.
dv - Display an event log (reboots, incidents of hydronic fluid too cold to flow, etc.).
fi - Force solar insufficiency (forced solar insufficiency is used for debugging).
gd - "Goad dog." Executes a 20 second delay to make the watchdog reboot the controller. Used for debugging.
m - Show free memory.
rb - Reboot
sb - Set number of times boiler has fired.
sc - Set realtime clock with values in this order: SECONDS,MINUTES,HOURS,DAYOFWEEK,DAY,MONTH,YEAR (no spaces, delimited by commas).
sD - Set realtime clock date, with values delimited by dash: YY-MM-DD (use 2 digit year, Y2K is over!).
sd - Set delay time before a change in thermistor readings leads to a change in collector behavior (used to minimize too many on-off commands to the pumps and open/close commands to the valves).
sf - Toggles the frozen state. Frozen means that the hydronic fluid is too cold to circulate. This state is triggered automatically, sometimes erroneously. If so, it clears itself after an hour.
sm - Set minimum temperature (in degrees Fahrenheit) in the roof panel for collection to commence in the summer season.
sn - Set the number of seconds to be added to the real time clock weekly to minimize drifting.
ss - Set season (1 is summer, 0 is winter). Season setting affects a number of behaviors. For example, in the summer, the electromechanical thermostat on the hot water tank is bypassed and maximum hot water temperature is instead handled by the sx setting (see below).
sT - Set realtime clock time, with values delimited by colon: HH:MM:SS (use 24 hour time, not 12 hour).
st - Set delay time of Master controller's loop (in tenths of a second, or deciseconds).
sW - Set day of week by integer (0 is Sunday).
sx - Set temperature (in degrees) of the maximum value for household hot water. Once that is reached, solar-heated fluid is sent through the slab.
us - Update menu system on Slave with latest internal data on Master.
wb - Write a byte of Master EEPROM. First value is address, second value is decimal byte to write.
wl - Write a long of Master EEPROM. First value is address, second value is decimal long to write.
xf - Force a check of fuel levels.