[Part 1] [Part 2] [Part 3] [Part 4] [Part 5 – ALISS] [Download]

Just FYI, ALISS v0.7.4 has changed so dramatically that a lot of what follows is no longer representative of how the programme operates. The basic structure is the same, but almost all of the variables have changed, among other things. That said, I have not yet finished testing 0.7.4, so this article will remain here as long as 0.7.3 is still available. I am also working on v0.8, which is a library version of ALISS, meaning you would be able to call aliss.programmeControl, for example. (07/Sep/15)

“Begin at the beginning,” the King said, very gravely, “and go on till you come to the end: then stop.” ― Lewis Carroll, Alice in Wonderland.

ALISS is the largest and most complicated programme and piece of hardware that I have designed and built.

It is just too big and complicated to give it the usual treatment that I give most of my projects here; all in it is 1,377 lines long. In itself, 1,377 isn’t a very big programme. There are many programmes that are much larger than ALISS, but this is the largest and most ambitious project I have undertaken. There are still a few things that need ironing out and shoe-horning in, but for the most part, ALISS is finished.


ALISS stands for Automated Low-power Irrigation & Security System. It does two jobs:

  1. Provide labour-saving operations
  2. Provide 24hr security operations

Previous versions of the Irrigation System provided a base level of labour-saving. There were no additional functions, and the system could not self-hydrate.

ALISS makes use of several I2C GPIO Expanders to increase the Arduino Mega’s 54 digital IO Pins to 86, allowing for multiple additional modules to be installed, such as:

  • an LCD Display
  • a Keypad
  • a 2.4GHz Radio
  • PIR Motion Detectors
  • Support for up to 16 solenoid valves
  • a 2G Cellular Phone

At its most basic level, ALISS allows the user to select one of ten different pre-defined Irrigation Programmes using the keypad.

At its most complicated, ALISS allows the user to select or cancel any one of those programmes by SMS message from anywhere in the world.


As I’ve already mentioned, ALISS is quite a complicated project, so I won’t go into a huge amount of detail. Instead, I’ll just give a more general explanation.



The original intention for ALISS was that it should “do more” than the previous version of the irrigation system. To achieve this, one function from the previous version, delay(), basically had to be deleted. There are a few occasions where delays are still used, but those are only debounce-critical areas.

Removing delay() adds the ability to do more than one thing at a time (sort of), but at the expense of simplicity.  If ALISS were sentient, then its goal would be to “always be looping”, and this is what we can achieve when we dump the delays.

When ALISS is functioning normally, either idle or irrigating, it is actually looping through 14 if statements over and over again, several times a second. ALISS will keep looping until one or more of those if statements causes it to divert. For example:

if (flag.updateSettings) {



If the flag flag.updateSettings is true, then perform the updateSettings function. Else, if the flag is not true, just move on.

That is the first thing ALISS does every time it starts a new loop. After doing that first if statement, ALISS moves on and does 13 more if statements, and then starts again, and keeps going until one of those flags stops the loop.

When one of those flag does stop the loop, the specified function is carried out, the flag is reset, and the loop carries on from where it left off, and then starts again. This approach allows us to have multiple things running at once, like a display and a keypad and a radio and a mobile phone, for example.

ALISS uses a lot of global variables, which is a good and a bad thing. I like global variables because they make the code look neater, however, they use up more memory, as they aren’t destroyed when they’re not in use. Considering I had to give up the simplicity when I moved from delay() to millis(), I wasn’t prepared to also give up neatness, so I have chosen to sacrifice memory for nice looking code. That said, most of the global variables and flags are bytes or bools as, in most cases, their values’ don’t exceed 255, and many that do are mostly constants anyway.

For instance, flag.activeProgramme will never exceed 255, but it is variable, so it is of type byte. Whereas show.progressReport will only ever be 325, so it is of type static const int.

Because I was sacrificing memory for neatness, I needed a way to save some of that active memory, otherwise the programme wouldn’t work properly. show.progressReport (325) is the memory address for the char “B” in the EEPROM. The full message is “BAY PASS REMAINS”, and this can be retrieved from the EEPROM using EEPROM.get(show.progressReport, var). Where var is a char array with size [17].

Using this technique, we can store a vast amount of data in the EEPROM and retrieve it with a recyclable (and importantly, destroyable) char to save on active memory constraints. For example:

char var[17];

lcd.setCursor(0, 0);

lcd.print(EEPROM.get(show.programmeSelect, var));

This accesses EEPROM memory location 116, saves the string into the char array var, and prints it onto the LCD display on line 0 at position 0.



programmeControl does four jobs:

If an irrigation programme is to be started, programmeControl sets up the crucial data trackers, so that ALISS can get in and out of the loop without issues.

If the user wishes to see the settings menu, programmeControl will display the chosen page from the settings catalogue

If the user wishes to see the programme menu, programmeControl will display the chosen page from the programme catalogue

If an active programme is to be checked, programmeControl will allow ALISS to check-up on the active programme

programmeControl must be called with a byte, e.g.: programmeControl(10), or programmeControl(flag.activeProgramme), etc.



customSequence, mcpCOMM and displayWriteInProgress deal with all the irrigation work.

customSequence keeps track of and administrates the valves to be activated and deactivated.

When a valve is to be activated, customSequence calls mcpCOMM(1), and to deactivate, mcpCOMM(0).

When the display needs to be updated to indicate work carried out, customSequence calls displayWriteInProgress().

customSequence must be called with two bytesfirst and last, e.g.: customSequence(1, 3) (which means, activate valves 1, 2 & 3 in sequence), or customSequence(1, data.numOfUsableValves) (which means, activate valves 1 thru (in my case) 11, in sequence).


There are many more functions that make the irrigation part of ALISS function properly, including flag.activeProgrammeBackupendProgramme()showMenu() and editSettings(), but the fundamentals are above.

There is, however, another way to access and control ALISS, by remote control.


Remote Operation

ALISS has a built in 2G mobile phone that can make and receive phone calls and SMS messages (as well as a few other things). This means that we can send ALISS a text message with the words ALISS_0xA and this has the same effect as pressing the A key on the keypad.

ALISS will receive that text message, determine whether or not the phone number that sent it is a registered user, whether or not that user has the requisite security clearance, carry out that order and then send an SMS reply.



Remote operation begins with an ISR called didReceiveSMSHail().

When a new message comes in, a pin on the phone goes low, which is ALISS’s indication that there is a new text message.

didReceiveSMSHail() does only two things:

Detaches the ISR, so that any additional text messages that come in don’t cause the ISR to re-trigger (which is something Vodafone do ALL THE TIME).

Makes flag.newSMS true, rather than false.

Back in the loop, one of the 14 if statements is:

if (flag.newSMS) {

// A new SMS was received

// read

// delete

// act


flag.newSMS causes:

  • didRetreiveNewOrders
    • readSMS
    • deleteSMS
    • didActionSMS
      • getUserClearanceLevel

If the user who sent the order is in the registered user list, and said user has sufficient security clearance to access said order, then ALISS will carry out that order and send an SMS reply.



flag.replyNeeded calls generateSMS() which generates the previously specified type of SMS message. This can be a reply confirmation, or this can be a security alert.

generateSMS builds one of three types of reply SMS, or one of four types of security alert.

Reply SMSs are sent only the user who sent the initial order and security alerts are sent to all users with a level 3 security clearance.

generateSMS does not require any arguments, instead, global variables are set before generateSMS is called, e.g.:

flag.outboundSMS = 1;

flag.smsReportType = 2;

byte done = generateSMS();

The above sends a progress report via SMS to the originating user. If done is 1, message sent successfully.

flag.outboundSMS = 2;

flag.securityAlert = 4;

byte done = generateSMS();

The above sends a security alert via SMS to all users with Level 3 Security Clearance. If done is 1, message sent successfully.


Again, there is more to Remote Operation than what I have talked about, but the fundamentals are above.


If you want more information about ALISS, use the Communicator.

To download ALISS, click here.

For the previous versions of the irrigation system, click here.


[Part 1] [Part 2] [Part 3] [Part 4] [Part 5 – ALISS] [Download]

Author: Dan

Share This Post On