
This tutorial will take approximately 30-60 mins.
There is a problem
You may have noticed that when you restart your ESP32 development board, the settings do not persist. Once power is removed from the memory, your playerID and teamID revert to their default values. This means you would need to change them every time the tagger powers up.
However, there is a better way to store the player ID and team ID using the ESP32 file system with LittleFS. This file system ensures that values remain intact even after firmware updates. As a result, you can easily update your entire collection of taggers with the same firmware while each gun retains its unique playerID and teamID.
Feature Cycle
We will continue to follow the feature cycle:

Before creating the next feature, save your project as “LaserTag_C07_File_System”.
Libraries, variables and setup()
LittleFS is already integrated into the core files for NodeMCU, so there is no need to install it separately in the Arduino software. Since we will be creating the files within the program rather than uploading them to the file system, there is also no need to install the upload tool.
Add the following library call to include the LittleFS library and declare the variable in the code:

Add the function call setupFileSystem();

New Tab – FileSystem, Functions and Code
The FileSystem tab includes several functions designed to assist with managing file reading and writing to the ESP32’s long-term memory. I have provided the text version of the code for you to copy and paste into your project.

void setupFileSystem(){
if(!LittleFS.begin(FORMAT_LITTLEFS_IF_FAILED)){ //format the filesystem if failed
Serial.println("An Error has occurred while mounting LittleFS");
debugInfo += "An Error has occurred while mounting LittleFS <br>";
}
else{
readPlayerFile();
readCloningDataFile();
}
}
void readPlayerFile(){// read file player.txt
//The first byte will be the playerID, the second byte will be the teamID
File playerFile = LittleFS.open("/player.txt", "r");
String playerFileContents;
if (playerFile) {
playerFileContents = playerFile.readString();
Serial.print ("saved player file contents: ");
Serial.println(playerFileContents);
//convert file string to variables
playerID = strtol(playerFileContents.substring(0,2).c_str(), NULL, 16);
Serial.println("playerID: " + String(playerID));
teamID = strtol(playerFileContents.substring(2,4).c_str(), NULL, 16);
Serial.println("teamID: " + String(teamID));
teamColour(); //update team colour
displayUpdate(); //update display with any new values
}
else {
Serial.println("No Player Data");
}
playerFile.close();
}
void writePlayerFile(){ // write to file or add new file called player.txt.
// The first byte will be the playerID, the second byte will be the teamID
File playerFile = LittleFS.open("/player.txt", "w+");
if (playerID <= 0x0F){ // this needs to be two digits
playerFile.print("0"); // this needs to be two digits
}
playerFile.print(playerID, HEX);
playerFile.print("0"); // TeamID always less than 2 Hex digits
playerFile.print(teamID, HEX);
playerFile.close();
// test saved file
playerFile = LittleFS.open("/player.txt", "r");
if (playerFile) {
Serial.print ("saved file contents: ");
Serial.println(playerFile.readString());
}
else {
Serial.println("No Player Data stored");
}
}
// stores the milestag clone signal
void writeCloningDataFile(){ // File "clone.txt"
// write to file or add new file called clone.txt
milesTagSettingsToArray(); // copy all milesTagettings to an array
File cloneFile = LittleFS.open("/clone.txt", "w+");
for (int j = 0; j < 44; j++){ // only interested in 44 bytes
if (milesTagSetting[j]<= 0x0F){ // this needs to be two digits
cloneFile.print("0"); // this needs to be two digits
Serial.print("0"); // this needs to be two digits
}
cloneFile.print(milesTagSetting[j], HEX);
}
Serial.println("");
cloneFile.close();
// test saved file
cloneFile = LittleFS.open("/clone.txt", "r");
if (cloneFile) {
Serial.print ("saved file contents: ");
Serial.println(cloneFile.readString());
}
else {
Serial.println("No Clone Data");
}
milesTagSettingsFromArray();//update game modes by running this
}
//opens the milestag clone signal and runs it thorugh the clone program to populate variables.
// All default variables are already set when varables were initilised
void readCloningDataFile(){
File cloneFile = LittleFS.open("/clone.txt", "r");
String cloneFileContents;
if (cloneFile) {
cloneFileContents = cloneFile.readString();
Serial.print ("saved milesTag file contents: ");
Serial.println(cloneFileContents);
Serial.print ("milesTag Array contents: ");
for (int i=0; i < 44; i++){
milesTagSetting[i] = hexStringToByte(cloneFileContents.substring(i*2,(i*2)+2));
Serial.print(milesTagSetting[i], HEX); Serial.print(",");
}
Serial.println("");
milesTagSettingsFromArray();
Serial.print("Milestag data read to and from file");
}
else {
Serial.print("No Clone Data");
}
cloneFile.close();
}
int stringToBinary(String s) {
int value = 0;
for (int i=0; i< s.length(); i++) // for every character in the string strlen(s) returns the length of a char array
{
value *= 2; // double the result so far
if (s.charAt(i) == '1') value++; //add 1 if needed
}
return value;
}
byte hexStringToByte(String recv){
char c[recv.length() + 1];
recv.toCharArray(c, recv.length() + 1);
return strtol(c, NULL, 16);
}
Make sure that all player-related web actions update the player file by incorporating the highlighted code.

Make sure that all game-setting related web actions update the clone file by incorporating the highlighted code.

Compile and test your code
Compile your code. You shouldn’t see any physical difference to your laser tag web interface, however, the settings should remain when you power off and power on your ESP32.
Explanation of player.txt
Read player.txt
A flowchart illustrating the process of reading the file has been provided below:

When the data file is not present on the system, the program will retain the existing values and will not update them from memory. File processing only occurs when the file is available.
Below is a representation of the data stored in the player.txt file. In this case, the player is represented in hexadecimal format, where 0F in hexadecimal corresponds to 15 in decimal. You can calculate this manually or use a hex calculator, such as the one available at: https://www.calculator.net/hex-calculator.html. In the MilesTag game, player 15 is named “Click”. In the example below, the teamID is set to 0, indicating the red team.

Christian Content
22 But be doers of the word and not hearers only, deceiving yourselves. 23 Because if anyone is a hearer of the word and not a doer, he is like a man looking at his own face in a mirror. 24 For he looks at himself, goes away, and immediately forgets what kind of man he was. 25 But the one who looks intently into the perfect law of freedom and perseveres in it, and is not a forgetful hearer but one who does good works—this person will be blessed in what he does.
James 1:22–25 (HCSB)
If our laser taggers cannot remember their identity, it leads to chaos of various kinds. The game will not function properly, reducing the taggers to mere mindless $10 toy guns.
The Bible emphasizes the importance of putting its teachings into practice. We must not only remember who we are, but also how to apply the Bible in our daily lives. This leads to good deeds and blessings in all that we do.
It is astonishing how this verse speaks so positively about the Bible. It is described as the perfect law of freedom. Many people view God’s word as a law that enslaves us. However, sin is deceptive. It is sin that enslaves us and compels us to continue sinning, whereas obeying God’s law liberates us from the bondage of sin. Sometimes, we forget the true goodness of God and his word, and this becomes a genuine issue with our own memory.