SMS generator control with Arduino
Driving 20km every day just to turn the generator and water pump on was becoming a drag, so I built an arduino solution with a GPRS shield, relay board, current sensor and real time clock to be able to turn them on remotely and monitor error conditions.
During testing I must have put too much current through one of the Phidgets sensors caused it stopped working properly, would only close, but not open – so switched it out for a 10A solid state version. Have been using the SMS command system for a week now without a hitch, basically I can start the generator, stop it, query it’s status and turn the timer on or off. If the unit detects any error condition, it will immediately shut the generator off and send an SMS alert.
The unit also has a built in warm up and cool down time for the generator and uses the current sensor to detect if the well is dry, i.e. if well is dry, pump stops, so current sensors can detect this and the arduino will shut down the generator. The current sensor will also detect if the generator didn’t come on or if the pump failed to turn on – or if the generator stopped when it should be running. All result in an error SMS being sent.
Had to mount the Arduino on the ceiling as the antenna cable wasn’t long enough
Relay box as close to the thick cabling as possible
Complete source code below, if anyone needs to rip bits out of it. Note that you’ll need to change the phone number, and the password “1234″, this password has nothing to do with the sim card, it’s just a number I’ve picked so that only people who know it can send messages to the generator.
#include "Wire.h" #include#define DS1307_I2C_ADDRESS 0x68 #define maxLength 200 #define PHONE 11111111111 String inString = String(maxLength); int HOUR = 21; int MINUTE_START = 01; int MINUTE_STOP = 55; boolean DEBUG = false; unsigned long starttime = 0; const unsigned long OVERRUN_TIME = 2UL*60UL*60UL*1000UL; const int GEN_START_PIN = 10; const int LOAD_PIN = 11; const int LED = 13; int GEN_START_DELAY = 20000; int GEN_STOP_DELAY = 20000; const int RETRY_LIMIT = 3; const int CURRENT_SENSOR_PIN = 2; const double MINIMUM_LOAD = 0.2; long WARMUP_DELAY = 60000; long LOAD_DELAY = 10000; const int GPRSonModulePin = 2; const double PUMP_LOAD = 4.0; double load = 0.0; boolean errorSent = false; boolean stoppedInWindow = false; boolean timerOn = true; int genState = 0; //0 = off, 1=running int pumpCommandState = 0; int genCommandState = 0; //0 = stop, 1 = start int error = 0; char* errorMsg[] = {"No error","Pump failed to start","Generator failed to start","Generator failed to stop","Generator overrun","Generator still running after stop signal"}; char* msg = ""; void getSerialChars() { while (Serial.available() > 0) { char inChar = Serial.read(); if (inString.length() < maxLength) { inString.append(inChar); } } } // Convert normal decimal numbers to binary coded decimal byte decToBcd(byte val) { return ( (val/10*16) + (val%10) ); } // Convert binary coded decimal to normal decimal numbers byte bcdToDec(byte val) { return ( (val/16*10) + (val%16) ); } void setDateDs1307(byte second, // 0-59 byte minute, // 0-59 byte hour, // 1-23 byte dayOfWeek, // 1-7 byte dayOfMonth, // 1-28/29/30/31 byte month, // 1-12 byte year) // 0-99 { Wire.beginTransmission(DS1307_I2C_ADDRESS); Wire.send(0); Wire.send(decToBcd(second)); // 0 to bit 7 starts the clock Wire.send(decToBcd(minute)); Wire.send(decToBcd(hour)); // If you want 12 hour am/pm you need to set // bit 6 (also need to change readDateDs1307) Wire.send(decToBcd(dayOfWeek)); Wire.send(decToBcd(dayOfMonth)); Wire.send(decToBcd(month)); Wire.send(decToBcd(year)); Wire.endTransmission(); } // Gets the date and time from the ds1307 void getDateDs1307(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year) { // Reset the register pointer Wire.beginTransmission(DS1307_I2C_ADDRESS); Wire.send(0); Wire.endTransmission(); Wire.requestFrom(DS1307_I2C_ADDRESS, 7); // A few of these need masks because certain bits are control bits *second = bcdToDec(Wire.receive() & 0x7f); *minute = bcdToDec(Wire.receive()); *hour = bcdToDec(Wire.receive() & 0x3f); // Need to change this if 12 hour am/pm *dayOfWeek = bcdToDec(Wire.receive()); *dayOfMonth = bcdToDec(Wire.receive()); *month = bcdToDec(Wire.receive()); *year = bcdToDec(Wire.receive()); } void switchModule(){ digitalWrite(GPRSonModulePin,HIGH); delay(2500); digitalWrite(GPRSonModulePin,LOW); delay(25000); if (DEBUG) { Serial.println("GPRS module turned on"); } } boolean genInTimerWindow() { byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); if (DEBUG) { Serial.print("Time: "); Serial.print(hour,DEC); Serial.print(":"); Serial.println(minute,DEC); } if (hour != HOUR) { stoppedInWindow = false; } if ((hour == HOUR) && (minute >= MINUTE_START) && (minute <= MINUTE_STOP)) { return true; } else { return false; } } void startGen() { if (DEBUG) { Serial.println("Starting gen"); } digitalWrite(GEN_START_PIN, HIGH); genState = 1; } void stopGen() { if (DEBUG) { Serial.println("Stopping gen"); } digitalWrite(GEN_START_PIN, LOW); genState = 0; } void connectLoad() { if (DEBUG) { Serial.println("Connecting load"); } digitalWrite(LOAD_PIN, HIGH); } void disconnectLoad() { digitalWrite(LOAD_PIN, LOW); if (DEBUG) { Serial.println("Disconnecting load"); } } double readLoad() { int load = analogRead(CURRENT_SENSOR_PIN); return (((double)load)*25.0/1023.0); } void deleteAllMsgs() { delay(1500); Serial.println("AT+CMGD=0,4"); delay(4000); } int smsCommand() { int retval=0; delay(1500); Serial.print("AT+CMGL="); Serial.print(34,BYTE); Serial.print("REC UNREAD"); Serial.println(34,BYTE); delay(3000); if (Serial.available() > 0) { inString = ""; delay(500); getSerialChars(); if (inString.contains("1234#")) { String command = String(20); command = inString.substring(inString.indexOf('#')+1,inString.length()); if (command.contains("start")) retval = 1; if (command.contains("stop")) retval = 2; if (command.contains("clear")) retval = 3; if (command.contains("status")) retval = 4; if (command.contains("timer on")) retval = 5; if (command.contains("timer off")) retval = 6; if (retval != 0) deleteAllMsgs(); } } return retval; } void sendSMSpreamble() { delay(1500); Serial.print("AT+CMGS="); Serial.print(34,BYTE); Serial.print(PHONE); Serial.println(34,BYTE); delay(1500); } void sendSMSappend() { delay(500); Serial.print(0x1A,BYTE); // end of message command 1A (hex) delay(5000); } void sendErrorSMS() { sendSMSpreamble(); Serial.print("Error: "); Serial.print(errorMsg[error]); writeStatus(); sendSMSappend(); } void sendStopSMS() { sendSMSpreamble(); writeStatus(); sendSMSappend(); } void writeStatus() { load = readLoad(); Serial.println(msg); Serial.print("L: "); Serial.println(load); Serial.print("Gen: "); Serial.println(genState); Serial.print("Runtime: "); Serial.print((millis()-starttime)/60000UL); Serial.println(" min"); Serial.print("Timer: "); if (timerOn) { Serial.print(HOUR); Serial.print(":"); Serial.print(MINUTE_START); Serial.print(" - "); Serial.println(MINUTE_STOP); } else { Serial.println("Off"); } } void sendStatusSMS() { sendSMSpreamble(); writeStatus(); sendSMSappend(); } void raiseError() { stopGen(); sendErrorSMS(); } void genStartSequence() { if (DEBUG) { Serial.println("Gen start sequence"); } disconnectLoad(); startGen(); delay(GEN_START_DELAY); load = readLoad(); if (DEBUG) { Serial.println(load); } if (load >= MINIMUM_LOAD) { starttime = millis(); delay(WARMUP_DELAY); connectLoad(); delay(LOAD_DELAY); load = readLoad(); if (load > PUMP_LOAD) { if (DEBUG) { Serial.print("Pump came on"); } } else { error = 1; if (DEBUG) { Serial.print(load); Serial.println(" was less than the pump load."); } } } else { error = 2; if (DEBUG) { Serial.print(load); Serial.println(" was less than the minimum load."); } } } void genStopSequence() { if (DEBUG) { Serial.println("Gen stop sequence"); } disconnectLoad(); delay(WARMUP_DELAY); stopGen(); delay(GEN_STOP_DELAY); load = readLoad(); if (load >= MINIMUM_LOAD) { error = 3; } else { sendStopSMS(); } } void blinkLED() { digitalWrite(LED,HIGH); delay(1000); digitalWrite(LED,LOW); } void setup() { Serial.begin(19200); pinMode(LED, OUTPUT); digitalWrite(LED, HIGH); pinMode(GEN_START_PIN, OUTPUT); digitalWrite(GEN_START_PIN, LOW); pinMode(LOAD_PIN, OUTPUT); digitalWrite(LOAD_PIN, LOW); Wire.begin(); delay(5000); starttime = 0UL; switchModule(); // swith the module ON Serial.println("AT+CMGF=1"); if (DEBUG) { //byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; //getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); //HOUR = hour; //MINUTE_START = minute; //MINUTE_STOP = MINUTE_START+1; WARMUP_DELAY=1000; LOAD_DELAY = 1000; GEN_START_DELAY = 2000; GEN_STOP_DELAY = 2000; } msg = "Module turned on."; //sendStatusSMS(); msg = ""; digitalWrite(LED, LOW); } void loop() { switch (smsCommand()) { case 1: genCommandState = 1; error = 0; timerOn = false; break; case 2: genCommandState = 0; stoppedInWindow = true; msg = "Stop signal from SMS"; break; case 3: error = 0; break; case 4: msg = ""; sendStatusSMS(); break; case 5: timerOn = true; sendStatusSMS(); break; case 6: timerOn = false; sendStatusSMS(); break; } if (error == 0) { errorSent = false; if (genState == 0) { starttime = 0UL; if ((timerOn) && (genInTimerWindow()) && (!stoppedInWindow)) { if (DEBUG) { Serial.println("In time window"); } genCommandState = 1; } if (genCommandState == 1) { genStartSequence(); } } else { if ((timerOn) && !genInTimerWindow()) { genCommandState = 0; msg = "Stopped by timer"; } if (readLoad() < PUMP_LOAD) { msg = "Stop signal from pump"; if (DEBUG) { Serial.println(msg); } genCommandState = 0; stoppedInWindow = true; } unsigned long time = millis(); if ((time - starttime) > OVERRUN_TIME) { error = 4; } if (genCommandState == 0) { genStopSequence(); } } } else { if (!errorSent) { raiseError(); errorSent = true; } } delay(2000); blinkLED(); if (DEBUG) { Serial.print("gen state="); Serial.print(genState); Serial.print(" Load="); Serial.println(readLoad()); } }
Exhaust silencer version 2.0
Going to make the expansion chamber smaller, so that it’s deeper underground, then funnel the gases through a maze made out of blocks filled with sand. There’s a big hole filled with builders sand that forms the center of this structure, with any luck the sand and the irregular direction of the baffled blocks and the fact that it’s all underground will make this super silent.
Perimeter foundations with sandy center:
And a maze of baffles including one at an odd angle to break the sound and try and reduce echoes. The gap between the blocks is always about three times the size of the surface area of the existing exhaust pipe, so shouldn’t have a problem with back-pressure on the engine.
After waiting for the cement to dry, I filled the holes up with sand, leaving a gap towards the top for the concrete to fill:
Used wooden blanks to form the roof and laid some mesh over it to add some strength to the croncrete
…and covered it all in concrete
PHPP completed!
Efibau has put the final touches to the PHPP so that we comply with the Passivhaus requirements. Finally we can start construction!
Radiator fan control and generator safey unit
Arduino with an ethernet shield and 2 analogue LM35 sensors.

I used some copper pipe to make better thermal contact with the radiator and engine block, and also to provide a place to mount the sensors. One went onto the outside of the engine block and one on top of the radiator (couldn’t find a better place). The radiator sensor consistently measures about 5 degrees hotter than the one on the engine block.



Heating System
Three heating sources will be connected to a central thermal 360L store. The idea behind the store is that it should stay topped up with solar hot water through most of the year, and then provide enough stored heat for at least 2 days of overcast weather. Heating demands will be minimal in winter of course, since this is a passivhaus
Thermal Store
360L thermal store from TiSun.
Solar Thermal
2.5 square meters of standard flat plate solar panel from TiSun.
Generator heat recovery
The cooling system on the generator could put out about 4kW of heat which will be recovered using a heat exchanger. The generator will be run for about 3 hours every 2 days, so that’s 6kWh per day which could raise the 500L store by 20 degrees (after the second day).
Wood Stove with backboiler
Will need 3kW of heat at the coldest time of the year to heat the entire house, this will mean a relatively small stove. I have the Morsoe Squirrel in mind, which outputs 4.6kW nominal and includes an optional 2.6kW boiler. But it doesn’t have an external air supply, so it will decrease the airtightness of the house.
The other option is the hunter herald 6, 7kW output total, 3kw for water heating and it supports an external intake, but it’s not as good looking as the Morsoe.
Gas boiler
The last fall back system will be the gas boiler plumbed into the Thermal store.
Radiant floor heating
For convenience we’ll include a radiant floor heating system if we’re too lazy to light the wood stove. To save on costs I plan to lay only half as much pipe, so with spacing double what it would normally be.
New control unit for Volvox generator
The Volvox generator didn’t arrive with a microprocessor based control unit; instead it had a number of discrete circuits to provide the required functions. Basically, the control unit should:
- Start the generator from a remote switch
- Stop the generator if the oil pressure is too low
- Stop the generator if the engine temperature is too high
- Turn the heater on before starting the engine
There’s a central unit in the Volvox manufactured by an Indian company called “GListen”, not much in it, instead the circuitry is distributed over 4 other units:
It looks as though each unit was soldered and assembled by hand! Now I can appreciate certain hand made items – but electronics isn’t one of them.
The main unit shipped to me was faulty so the chaps at Vidhata shipped a replacement unit, that too didn’t work… until I discovered the fault was a dodgy connection. By this time I’d given up on all these bits of circuitry and instead bought a proper microprocessor controlled unit from Deapsea PLC, the DSE3110.
It replaces all those boxes and the main GListen unit; it’s fully programmable with a PC so configuration is a snap and it offers all the important safety features including a few additional ones:
- Generator stop for under or over voltage
- Stop for under or over frequency
- Stop for under or over RPM
- Monitoring of battery voltage
All the values are completely configurable from the PC software.
It works wonderfully and now the control box is a bit cleaner too:
Just need to find a bit of metal so that I can mount it properly… the ductape isn’t a long term solution
The RPM monitor that shipped with the generator is also a GListen unit and it’s been showing erroneous values sometimes displaying 4000+ RPM when the generator is really only doing 1500. Hopefully that problem will also be solved by the Deepsea unit as it also displays RPM.
Generator exhaust expansion chamber
Hopefully this will attenuate the noise of the vegetable oil generator exhaust even more. The chamber itself will be buried up to the three exhaust holes. The blocks on top are to retain the soil that will cover the roof of the shed.

Built the contention walls around the door too, now just need the ventilation to go in and it will be ready for water proofing.

SMA Sunny Island AC Coupling
Designing off-grid wind and solar installations differs from grid tied installations in a number of important ways such as:
- The solar array must be in a certain restricted voltage range
- The solar and/or wind generator must be kept very close to the battery bank
- Expanding the system in the future can involve complex wiring
SMA has addressed many of these issues in their Sunny Island product range by offering a unique system configuration where all power generation sources can be connected directly to the AC bus as illustrated below:

The system certainly is innovative and offers a number of advantages over traditional DC coupled systems, but there are potential downsides too.
In this article, I’ll explore the advantages and disadvantages of AC side coupling using the Sunny Island and Sunny Boy with more traditional DC side coupling using the Outback MPPT charge controller.
Flexibility and simplicity in wiring
Using the 230V AC bus as the central component of the off-grid system means that wire size can be reduced. Photovoltaic panels and wind turbines can be located up to 1 km from the Sunny Island and the batteries. And the system can very easily be expanded by simply connecting more Sunny Boys or Windy Boys to the AC bus. Since almost everything is garden variety 230V AC the system could easily be installed by any electrician familiar with domestic wiring – no need for complicated DC wiring.
With a DC connected system, even with an MPPT charger, you could still only use a maximum voltage of about 120V between panels and charger, which means that wires would have to be thicker and/or shorter.
The Sunny Island changes the grid frequency to manage the available and required power. This means that you could connect frequency dependent relays to the Sunny Island mini-grid to turn optional loads on or off (This feature is built into the Sunny Island through a relay anyway, but you could do it externally based solely on grid frequency). You could also attach synchronous generators that would start or stop based on the grid frequency. Flexibility is the Sunny Island’s middle name.
Cost
SMA’s strategic decision to promote AC side connections was more likely made in their board room, not in their engineering department. SMA are well known for the grid tied Sunny Boy and Windy Boy inverters and the Sunny Island was a relatively new addition to their product line, so it makes a lot of business sense for them to promote their existing products instead of branching out into charge controllers.
Inverters cost substantially more than charge controllers of the same capacity. Taking the popular Outback FM80 charge controller which could charge a 48V battery from a 3.8kW PV array, it retails for about 700 Euros. An SMA Sunny Boy inverter 3800 inverter retails for about 1700 Euros, more than double the cost! That’s an additional 1000 Euros that could be spent on more PV.
SMA do produce a 40A charge controller for smaller systems, but this retails for about 900 Euros – again more expensive than the Outback which provides double the charging capacity.
Now there are some cost savings to be made by going the AC route with the Sunny Boys which I’ll touch on in the next section…
Additionals
On a DC connected system, in addition to the charge controller you’d also typically need a combiner box to parallel the PV strings and a DC breaker to disconnect the PV panels. But when using a Sunny Boy these ancillaries are sometimes not required. The Sunny Boy includes a built in ESS switch for disconnecting the PV from the inverter so there’s no need for a dedicated DC breacker. Most models of Sunny Boy also include connections for up to 3 parallel strings. The more powerful models may even include more than 1 MPPT tracker so that you can connect strings with differing orientations or a string that is partly shaded. Although these ancillary items could be saved, they might still not warrant the additional costs of the Sunny Boy.
Efficiency
This is potentially a big issue for AC side coupling. There are two important factors at work when considering AC side connection of power sources:
- Battery charging is less efficient because of double conversion from DC PV to the AC bus and then from the AC bus through the Sunny Island back to DC charging of the batteries.
- Direct consumption of PV power on the AC bus is more efficient because of the high efficiencies of the Sunny Boys (up to 97%, but typically 95%).
This means that the system will be more or less efficient based on how much power is consumed directly off the AC bus and how much is consumed from the batteries. SMA’s training material rather unhelpfully compares the best case AC side coupling with the worst case DC side coupling. I used these figures to instead compare best case AC side coupling with Sunny Boys compared to best case DC side coupling with the Outback FM80. The efficiency values I used were as follows:
| Sunny Boy | 95% |
| Sunny Island Charging | 92% |
| Sunny Island Inverting | 95% |
| Battery charging | 85% |
| Outback FM80 charging | 98% |
Using these values, we can then compare the efficiencies of the 2 systems based on how much power is consumed directly off the AC bus:

Therefore if you’re using 60% of the power directly from the AC bus then the AC side coupling starts becoming more efficient than DC side. But the efficiency of an off-grid PV system is most important in winter, when there’s the least amount of sun. In fact, if you’ve designed an off-grid home then the size of the PV array will largely be determined by the low sun hours in winter and the depth of your wallet. Winter is when efficiency matters and this is precisely the time when you would typically be charing and using more power from the batteries. Averaging 60% usage directly from the AC bus might be applicable to certain systems, such as businesses or farms that don’t have a constant energy requirement throughout the year, but that have peak requirements in the summer months. For off-grid homes that have a more or less constant energy requirement throughout the year and much less sun in winter, DC side charging remains the most efficient.
You can find the full spreadsheet used to calculate the efficiencies here.
Flexibility in PV panels
An additional complication with traditional DC side coupling of PV panels is that you are often limited in choice for PV panels because they have to conform to smaller voltage tolerances. MPPT charge controllers have increased this range with their ability to accept up to 140V from the PV panels and convert that to charge a battery bank of 24 or 48V, but still there are limitations in how you configure the strings and which PV panels can be used.
Since AC side coupling involves using standard Sunny Boy inverters that are usually used for grid tied applications, it means you have complete freedom in choosing PV panels and can work with much higher string voltages, typically up to 500V per string. This could also contribute to cost savings because it might mean that you could use thin-film panels for your off-grid home that would otherwise not fit within the voltage ranges for charge controllers. Higher voltages also mean thinner and cheaper cabling in the PV array.
Conclusions
The choice between AC or DC side coupling essentially boils down to a question of cost versus flexibility.
AC side coupling with Sunny Boys is more expensive than DC, both in terms of capital outlay as well as lost efficiency in winter months. But it offers the advantage of simpler and cheaper wiring and a wider choice in PV panels and string configurations which might offset these costs. The full mini-grid management features allows for added flexibility in expanding off-grid systems and in connecting power suppliers some distance away from the batteries. This added flexibility will likely be less important for off-grid holiday homes or partially occupied homes but increasingly important for larger systems such as farms or other commercial environments or for rural electrification of villages.
AC side coupling is an innovative feature and certainly allows for a freedom in off-grid system design that was not before possible. But freedom comes at a price, and whether it will be worthwhile for your next system really depends on the application and the factors listed above.
The Volvox generator arrives
Welcome to Casa Nogal de las Brujas
An experiment in creating a sustainable, energy efficient home in the Aragonese countryside.




















