Introduction: Task Manager - a Household Chore Management System

I wanted to try to address a real problem faced in our household (and, I imagine, that of many other readers), which is how to allocate, motivate, and reward my children for helping out with household chores.

Up to now, we've kept a laminated sheet of A4 paper stuck to the side of the fridge. It has a grid of tasks printed on it, with associated amounts of pocket money that could be earned for completing that task. The idea is that each time one of our kids helps out with a chore, they get a tick in that box and, at the end of each week, we add up the money earned, wipe the board and start again. However, the list of tasks is out-of-date and hard to change, we sometimes don't remember to wipe the board clean each week, and some tasks need to be performed with different frequencies - some would ideally be done daily, whereas others might only be once a month. So, I set about creating an Arduino-based device to address these issues - my intention was to create something that allowed for easy addition/removal/updating of tasks, a streamlined mechanism for recording when a task had been done and allocating credit to the appropriate person, and a way to keep track of different schedules and frequency with which different tasks need to be performed, and highlight overdue tasks. And this instructable will show how the resulting "Task Manager" device came out.

Step 1: Hardware

The project makes use of several well-used and documented hardware components:

  • Arduino UNO/Nano - this is the "brains" of the system. The onboard EEPROM memory will be used to save the state of tasks even when the system is powered off. For ease of wiring, I've mounted the Nano on a screwshield, but you could solder or use crimped connections to the GPIO pins instead if you prefer.
  • Real-Time Clock (RTC) module - used to record the timestamp at which tasks were performed, and, by comparing the last time to the current time, determine which tasks are overdue. Note that the unit I received was designed to be used with a rechargeable LiPo battery (LIR2032). However, I'm using a non-rechargeable CR2032 battery, so I needed to make a few modifications to disable the charging circuit (you don't want to try to recharge a non-rechargeable battery, or you might face an explosion....). Specifically, I removed resistors R4, R5, and R6, and the diode marked D1. I then created a solder bridge to short across where R6 had been. These changes are illustrated in the photo below.
  • ISO14443 RFID reader + one tag per user- as a way of "gamifying" the system, each of my children has their own unique RFID tag. Selecting a task and then swiping their tag across the reader will be the mechanism used to mark a task as complete
  • 16x2 LCD display - used to provide the user interface to the system. By using a board that has an integral PCF8574A backpack, the board can be connected via an I2C interface to the Arduino, which simplifies the wiring significantly.
  • Rotary Encoder - will be the main control knob which users will turn to select different available tasks
  • Wago connectors - these snap-shut connectors are a convenient way to wire components together or create simple busses for several modules that each require common ground or 5V supply.

Step 2: Wiring

  • The 16x2 LCD display and DS1307 RTC both use an I2C interface, which is convenient as it makes the wiring much simpler, requiring only a pair of wires going to the A4 (SDA) and A5 (SCL) pins of the Arduino.
  • The MFRC-522 RFID reader uses an SPI interface, which uses fixed hardware pins 11 (MOSI), 12 (MISO), and 13 (SCK). It also requires a slave select and reset line, which I've assigned to pins 10 and 9 respectively.
  • The rotary encoder requires a pair of pins. For optimal performance, it's best if these pins can handle external interrupts, so I'm using digital pins 2 and 3. You can also click the encoder in as a switch, and I've wired this into pin 4. Even though it's not currently used in the code, you might find it useful for adding additional features!
  • For convenience, I'm using WAGO 222-series connector blocks. These are snap-shut connectors that provide a robust, easy way of connecting anywhere between 2 and 8 wires together, and are very convenient for Arduino projects that require several modules to share a ground or 5V line, or where you have multiple devices on the same I2C or SPI bus, say.

The diagram illustrates how everything is wired together.

Step 3: Construction

I created a very basic 3D printed case to house the electronics. I placed some magnets on the back so that the unit could be secured onto the side of the fridge, just as the previous printed list was. I also left the USB socket exposed, since this would be used if new tasks needed to be added to the system, or to log on and download a set of data showing completed tasks etc.

I didn't save the STL files after printing, but there are plenty of similar (and, probably better!) cases available on thingiverse.com. Alternatively, you could construct a nice wooden box, or just use an old cardboard box or tupperware container to house the electronics.

Step 4: Code

The fully-commented code is attached as a download below. Here's a few of the more important points to note:

  • I've created a custom struct, "task", which is a unit of data that encapsulates all of the properties of a task in a single entity. Tasks consist of a name, which will be how they appear in the LCD display (and hence limited to 16 chararacters), the frequency with which they need to be performed, and when and by whom they were last completed.
struct task {
  char taskName[16]; // The short, "friendly" name for this task as will appear on the display
  int repeatEachXDays; // Regularity, in days, with which this task is repeated. 1=Daily, 7=Weekly etc.
  unsigned long lastCompletedTime; // Timestamp at which this task was last completed
  int lastCompletedBy; // ID of the person who last completed this task
};
  • The main data structure is called "taskList", which is simply an array of separate tasks. You can define whichever tasks you want here, which are initialised with a value of 0 for the time at which they were last completed, and -1 for the ID of the user that last performed them.
task taskList[numTasks] = {
  { "Clean car", 7, 0, -1 },
  { "Change sheets", 14, 0, -1},
  { "Mow lawn", 7, 0, -1 },
  { "Hoover", 3, 0, -1 },
  { "Walk dog", 1, 0, -1 },
  { "Tidy Bedrooms", 7, 0, -1 },
  { "Water plants", 2, 0, -1 },
  { "Upstairs toilet", 7, 0, -1},
  { "D/stairs toilet", 7, 0, -1 },
  { "Hoover", 3, 0, -1 },
  { "Clean shower", 7, 0, -1 },
};
  • In the constants section at the top of the code, there is a single byte value called "eepromSignature". This value is used to determine whether the data stored on EEPROM is valid. If you change the structure of the taskList item, by adding or removing tasks, or adding additional fields, say, you should incremement this value. You can think of it like a basic version numbering system for the data.
const byte eepromSignature = 1;

On startup, the program will only attempt to load data stored in EEPROM if it matches the signature of the data defined in the code.

void restoreFromEEPROM() {
   int checkByte = EEPROM.read(0);
   if(checkByte == eepromSignature) {
      EEPROM.get(1, taskList);   
   }
}
  • The LCD display and the RTC module use an I2C interface to communicate with the Arduino. This requires every device to have a unique I2C address. I've tried a couple of different 16x2 display boards, and some seem to use the address 0x27, while other seemingly identical boards use 0x3f. If you find your display just shows a series of squares and no text, try changing the address value defined in the code here:
LiquidCrystal_PCF8574 lcd(0x27); 
  • When an RFID tag is detected, the code reads the 4-byte identifier, and uses it to attempt to look up the corresponding user from the table of known users. If the tag is not recognised, the 4 byte identifier will be sent to the serial monitor console:
int GetUserFromRFIDTag(byte RFID[]){
  for(int i=0; i<numusers; i++)="" {<br=""><numUsers; i++) {   <br>    if(memcmp(userList[i].rfidUID, RFID, sizeof userList[i].rfidUID) == 0) {
      return userList[i].userID;
    }
  }</numusers;>

Serial.print(F("Unknown RFID card detected: "));
  for(byte i=0; i<4; i++) {
    Serial.print(RFID[i]<0x10 ? " 0" : " ");
    Serial.print(RFID[i], HEX);
  }
  return -1;
}

In order to assign a tag to a user, you should copy the ID displayed and insert the 4-byte value into the users array at the top of the code, next to the corresponding user:

const user userList[numUsers] = {<br>  { 1, "Ginny", {0x00, 0x00, 0x00, 0x00}},
  { 2, "Harry", {0x12, 0x34, 0x56, 0x78}},
  { 3, "Ron", {0xE8, 0x06, 0xC2, 0x49}},
  { 4, "Hermione", {0x12, 0x34, 0x56, 0x78}},
  { 5, "Alastair", {0x12, 0x34, 0x56, 0x78}},   
};

Step 5: Usage

If you've made it this far, the usage of the system should be fairly implicit from the code; at any time, users can turn the rotary knob to scroll through the list of available tasks. Chores that are overdue are marked with an asterisk after their title.

Having selected a chore to carry out, users can then scan their own unique RFID fob across the reader to mark the task as complete. Their ID and the current time will be recorded and saved to the EEPROM of the Arduino.

In order to first set up the correct RFID tags, you should run the sketch with the Arduino serial monitor attached. Scan each tag and take note of the 4-byte hex UID value displayed on the serial monitor. Then modify the userlist declared at the top of the code to assign this tag ID to the appropriate user.

I considered adding functionality to print out a report showing all tasks completed, by user, during the last week in order to allocate the appropriate pocket money reward each week. However, as it happens, my children appear to be satisfied by the novelty of using the system to have forgotten about the pocket money rewards completely! This would be a fairly simple addition however, and is left as an exercise for the reader :)

Arduino Contest 2019

Participated in the
Arduino Contest 2019