Editorial Solution

From the task, we can understand that we have to build a Unit preference-saving system.

We need EEPROM to save the preferences, so we can retain it even after power off/ restart.

Let’s design the system

We have 4 measurements as follow 

  • Temperature: Celsius, Fahrenheit
  • Distance: Kilometers, Miles
  • Weight: Kilograms, Pounds
  • Volume: Liters, Gallons

Now let’s allocate the address for each parameter in EEPROM location 0,1,2,3 respectively, where we can save preferred units in either 0 or 1. 

I.e. for Temperature: EEPROM Location will be “0x00” and value stored: (0 for Celsius and 1 for Fahrenheit).

For the first run, we can save all preferences as 0 (Default Preferences). 

We can retrieve each preference from EEPROM locations and print the corresponding unit on the screen. 

Then we will ask the user to change the preference. Based on the user’s input, we will save the corresponding value (0,1) to the EEPROM location.

For restoring to default, we can set all the parameter values to 0.

Code

#include <EEPROM.h>



// Constants for menu options
const char* tempUnits[] = {"Celsius", "Fahrenheit"};
const char* distUnits[] = {"Kilometers", "Miles"};
const char* weightUnits[] = {"Kilograms", "Pounds"};
const char* volumeUnits[] = {"Liters", "Gallons"};



// Struct to hold user preferences
struct Preferences {
 uint8_t tempUnit;   // 0: Celsius, 1: Fahrenheit
 uint8_t distUnit;   // 0: Kilometers, 1: Miles
 uint8_t weightUnit; // 0: Kilograms, 1: Pounds
 uint8_t volumeUnit; // 0: Liters, 1: Gallons
};



Preferences userPreferences;



// EEPROM address for preferences
const int eepromAddress = 0;



void setup() {
 Serial.begin(9600);



 // Load preferences from EEPROM
 EEPROM.get(eepromAddress, userPreferences);



 // Sanity check for preferences
 if (userPreferences.tempUnit > 1 || userPreferences.distUnit > 1 ||
     userPreferences.weightUnit > 1 || userPreferences.volumeUnit > 1) {
   resetPreferences();
 }



 displayCurrentPreferences();
 displayMenu();
}



void loop() {
 if (Serial.available()) {
   handleMenuInput();
 }
}



void displayCurrentPreferences() {
 Serial.println("\nCurrent Preferences:");
 Serial.print("1. Temperature: ");
 Serial.println(tempUnits[userPreferences.tempUnit]);
 Serial.print("2. Distance: ");
 Serial.println(distUnits[userPreferences.distUnit]);
 Serial.print("3. Weight: ");
 Serial.println(weightUnits[userPreferences.weightUnit]);
 Serial.print("4. Volume: ");
 Serial.println(volumeUnits[userPreferences.volumeUnit]);
 Serial.println();
}



void displayMenu() {
 Serial.println("\nMenu Options:");
 Serial.println("1: Set Temperature Unit (0: Celsius, 1: Fahrenheit)");
 Serial.println("2: Set Distance Unit (0: Kilometers, 1: Miles)");
 Serial.println("3: Set Weight Unit (0: Kilograms, 1: Pounds)");
 Serial.println("4: Set Volume Unit (0: Liters, 1: Gallons)");
 Serial.println("5: Reset to Default Preferences");
 Serial.println("Enter your choice and the unit separated by a space (e.g., 1 0 for Celsius).");
}



void handleMenuInput() {
 // Wait for complete input in the form: <option> <value>
 while (Serial.available()) {
   String input = Serial.readStringUntil('\n'); // Read full line input
   input.trim(); // Remove leading/trailing spaces



   int spaceIndex = input.indexOf(' ');
   if (spaceIndex == -1) { // No space found, invalid input
     Serial.println("Invalid input! Format should be <option> <value>.");
     displayMenu();
     return;
   }



   // Split the input into option and value
   int option = input.substring(0, spaceIndex).toInt();
   int value = input.substring(spaceIndex + 1).toInt();



   switch (option) {
     case 1: // Temperature
       if (value >= 0 && value <= 1) {
         userPreferences.tempUnit = value;
         savePreferences();
       } else {
         Serial.println("Invalid input for Temperature!");
       }
       break;
     case 2: // Distance
       if (value >= 0 && value <= 1) {
         userPreferences.distUnit = value;
         savePreferences();
       } else {
         Serial.println("Invalid input for Distance!");
       }
       break;
     case 3: // Weight
       if (value >= 0 && value <= 1) {
         userPreferences.weightUnit = value;
         savePreferences();
       } else {
         Serial.println("Invalid input for Weight!");
       }
       break;
     case 4: // Volume
       if (value >= 0 && value <= 1) {
         userPreferences.volumeUnit = value;
         savePreferences();
       } else {
         Serial.println("Invalid input for Volume!");
       }
       break;
     case 5: // Reset Preferences
       resetPreferences();
       break;
     default:
       Serial.println("Invalid Menu Option!");
   }



   // Display updated preferences and menu
   displayCurrentPreferences();
   displayMenu();
 }
}



void savePreferences() {
 EEPROM.put(eepromAddress, userPreferences);
 Serial.println("Preferences Saved!");
}



void resetPreferences() {
 userPreferences = {0, 0, 0, 0}; // Default: Celsius, Kilometers, Kilograms, Liters
 savePreferences();
 Serial.println("Preferences Reset to Default!");
}

Code Explanation


Menu Input Handling

  • The input format is <option> <value> (e.g., 1 0 to set the temperature to Celsius).
  • Parse and validate the input, updating the relevant field if valid.
     
int option = input.substring(0, spaceIndex).toInt();
int value = input.substring(spaceIndex + 1).toInt();
switch (option) {
  case 1: userPreferences.tempUnit = value; savePreferences(); break;
  ...
}

 

We can also try implementing

  • Since every measurement has 2 options, instead of saving the Struct we can fit all options in one byte and save 3 cells. 
  • Hint -> You can assign each bit to different measurements.

 

Output Video

Submit Your Solution