Balance Anytime by the Joey Chestnuts

Josh, Vincent, and Maeve

Two wood boxes with white paint primer. Left one has a face ~12"x11" with a door in it slightly ajar. It's other face is ~3"x12", and has the sensor and display. The smaller box is about 4"x6"x3", with the largest of those faces having the keypad and display. Shot on a clean background, and the lighting is noticeably a bit more moody than it needs to be. Both displays read "$25.00".

Final product. 

Locker unit with a fingerprint sensor, balance display, and locking latch (left). Office unit with a number pad and balance display (right).

Introduction

This device is the product of the Joey Chestnut team's final project for Carnegie Mellon's 60-223 Physical Computing course, in collaboration with Community Living And Support Services (CLASS).  The goal of this project is to solve a problem for a client at CLASS through means of a physical computing device, meaning any physical device that is interactable and takes advantage of electronics. The team takes an understanding of a problem in the client's life through interviews and creates an assistive devices to help solve that problem. We worked with Zajkora form CLASS in this project to understand what need she would most like us to address, and how we could assist in a way that would be practical and to her standards. Additional context such as design drafting and meeting notes between the Joey Chestnuts and Zajkora can be found in our Interview Documentation page on this site.

What we built and How it Helps

This project aims to solve the problem of Zajkora having difficulties checking her remaining balance at CLASS since her weekly allowance is kept in a safe locked in a room only accessible by CLASS staff members. She currently has to seek assistance from a staff member to check the safe if she would like to budget for upcoming spending. Our product aims to solve this by allow Zajkora to check her balance at her shelf in the hallway without needing to ask a staff member. This is done by building a two part solution consisting of a logging device in the office for the staff member to update whenever money is deposited or withdrawn from the safe, and a separate device in Zajkora's shelf that is able to retrieve the balance number wirelessly and be able to display it at any time. The logging device in the office has a simple number pad and screen to enter a balance number. The shelf device has a finger print sensor registered to Zajkora and a number display that will show her balance after Zajkora presents her fingerprint. The shelf device is especially designed to fit perfectly into Zajkora's shelf with easily accessible screen and fingerprint sensor. It also uses the remaining space in the box by providing a locked storage compartment that also unlocks with Zajkora's fingerprint. 

BothFullRunThru.mp4

Basic demo of the final product running through unlocking, updating the balance, and then relocking.

DoorandServoDemomp4.mp4

Demo of the locking-latch mechanism and different fingerprint registration responses on the locker unit (Locker-box).

The light on the sensor will flash blue to indicate it is currently detecting a finger and is checking if that fingerprint is registered. Once it's flashed three times, the finger may be removed and it will count the print as either registered or unregistered. 

If the print is registered, the light will glow pink, the locking-latch servo will retract, and the balance will display. These will continue happening until the box is relocked.

The box is relocked by any touch, regardless of if that fingerprint is registered. It does not require the finger to be held down and the balance is immediately hidden to give Zajkora privacy if she wishes to quickly hid her balance.

Attempting to unlock with an unregistered fingerprint does nothing but give you  an indicator light for "not accepted".


SafeBoxDemo.mp4

Demo of the office unit's screen (the Safe-box).

The safe-box gets external power, so it doesn't turn off unless it's unplugged, although it has a "sleep mode" to save electricity.

Sleep mode locks the keypad so you cannot accidentally delete the balance . From sleep mode hitting any button takes it to the "welcome screen", which unlocks only the "#" and "*" buttons.

In the "* to input value" window, the text "Value saved." only appears after the 4th digit is entered. This is a lie- the new value was constantly being saved/updated as long as  the "Enter new value:" window was up.

The safe-box  is constantly storing and transmitting the balance it holds, even in sleep mode. The locker-box constantly holds a variable for the money balance, but only looks for a radio signal when it's unlocked. This is why you can see it briefly show the previous balance when the display turns on before changing to $12.00.

Box lays flat with its larger side on the table, door side facing skyward. Interior of the box is pale wood, not white primer like the outside. The smaller box is standing in the background of the photo.

Interior of locker unit includes a magnet to hold the door shut and access to the battery panel. The interior of the hinged door on it is covered with foam to let it close quietly. All electronics are stored in the front bit.

It is indeed a photo mainly focused on the hinges/ backside of the locker box. They're small (~1" long), and look like they're maybe a brassy metal.

Hinges on the back side of the locker unit. Office unit only has the keypad, screen, and jack for external power on the outside,

Locker-box is in foreground, Vincent's in the background down a hallway waving the office-box to get the locker-box to update (it's a gif). He's about 25" away.

Demo of the boxes communicating from max-distance.

Example use case

On a Wednesday evening, Zajkora plans out her following day going to the mall. She has some ideas of what she wants from the mall but is not sure how much allowance she has remaining. There is no staff member in sight to check the safe for her, so she goes to her shelf in the hallway. Since she would not like everyone else to be able to see her balance, it is not shown until she presents her fingerprint.  She sees that she has 15 dollars left to spend, and plans accordingly.

After her trip to the mall, Zajkora goes to retrieve her notebook locked in the box's storage compartment using her fingerprint, and is able to check how much she spent at the mall while doing so. At that moment, she also decides she will paint the box with pretty flowers during next art class, which is possible because the box is made of wood and already has a coating of primer to allow for custom art. 

How we got here

Prototype

The main goal of our prototyping stage was to validate if our plan for wirelessly transmitting data would be possible, and to draft how the box in the locker would be designed.


Transceivers:

As a team, we have experience using the other components on this build, but not the wireless transceivers. It is a core functionality of our product so we needed to make sure it is possible before moving on. 

In the photos below, the two Arduino Unos are stand-ins for our two devices that will communicate with each other. Each is hooked up to a wireless transceiver.  In the left image, the one representing the office unit has a button because it will be the one sending the signal, and the one representing the locker unit has a LED because it will be the one receiving the signal.  Getting even a basic "On/Off" signal to send proved harder than we thought. We ended up getting help from our classmate Aiden since he had working code for the transceivers used in his project here. In the end, we found that the issues we were having with the transceivers were caused by using  transceivers that has at some point been plugged into 5V rather than 3.3V. This appeared to have been the case with several transceivers we tested from the classroom, all or most of which were probably put back in the drawer.

Arduinos with transceivers & button & led hooked up as described above. Both sitting on table not very far apart from eachother. Gif of pressing the button, LED on the other turns on and off.

Testing communication with wirelessly turning on and off a LED.

Shot of the same parts being assembled on a table next to a laptop as we test it.

Connecting both Arduinos to test the wireless transceivers. 

Another issue that was discovered with the transceivers once they were working with a single button and LED, was that using them at the same time as a keypad caused the signal to send sporadically. The solution to this was to unplug the keypad, and then plug it back into a different Arduino with the same pinouts.

Box design:

The box we used for the prototype is cut out of a large sheet of wood and taped on the edges to form a complete box, slots were cut out to temporarily fit the balance display and fingerprint sensor. It serves the purposes of a trial run at laser cutting wood, physical object to gauge size requirements, and a hands on object for our client to hold and look forward to.

Box same dimensions as the final one, full frame. It's of a dark brown wood, no door, and taped at edges.

The prototype shelf unit with a full box but no internals.

Photo of Zajkora's locker, with dimensions drawn over it digitally in post. Locker is at roughly eyelevel, maybe a bit lower. You can see her bag/ daily belongings kept in it, taking up most of the room.

Space requirements for the shelf unit. We decided the display and fingerprint sensor needed to be at the front of the shelf to be accessible based on Zajkora's height.

Our client Zajkora came to visit during our prototype critic, and she had some valuable feedback on potential features. Apart from features like an iPad screen that was not taken due to cost and complexity, we did implement a couple of her other suggestions. The box was just planned to be empty space that is only there to make the device accessible from the edge of the shelf. However we realized in conversation that we can use the already planned fingerprint sensor to make a lock box in that empty space. Zajkora also mentioned that she like the colors white and gold as well as liking painting, which resulted in out decision to put paint primer on the box so she can decorate the box.

Everyone in it looks really cute :3

Photo of the team with Zajkora in the middle when she visited us. The prototype box can be seen behind Vincent (with red hair).

Once we had the transceivers able to transmit a simple On/Off message and knew how we wanted to fit components in the box, we began wiring the rest of the electronic features and began writing the final software.

Loose sketch of parts drawn on white-board table

Drawing a visual diagram of where components will be placed.

Jumble of Arduino wires.

Wiring other components like the balance displays.

jumble of Arduino wired, but it's a gif where the LDC screen changes through it's various screens

Testing office unit LCD screen.

Process

3D Modeling

The entire shelf unit has a digital recreation make in SolidWorks. This is an good way to sure everything fits in our design. Since all of our box parts are either 3D printer or laser cut, we can be confident that our digital CAD can be translated to physical object with precision. The physical devices are then laser cut out of plywood and wood glued together. The laser cutter cuts out intersecting edges that we attach and glue. The edges are then sanded down for a smooth finish and primed for painting.


side view 3D model of the locker-box with components mapped out

The 3D model prototype. It has the box external and internal dimensions, as well as most of the electronics section. The 3D printed part is visible in white, as well as the battery box below it.

The Door

One of the most difficult parts of assembling the shelf unit is the hinge. We used small door hinges from Home Depot and tried to directly bolt on the panels. We had significant trouble with clearances, resulting in the door not closing all the way. The hinge was removed and reattached 7 times in total, with small adjustments and sanding of parts in between. Eventually we came to a satisfactory door by adding black felt on the inside of the door for cushioning and a magnet on one corner to help the door stay closed. 


There was a handle designed for the door but it was later replaced with a round notch in the side of the door. This is because Zajkora requested we allow her to put a piece of paper on the front of the door so that she can place artwork or her schedule there to make it always visible. We did this by attaching a sheet protector on the door so a piece of letter size paper can be inserted. This sheet protector is just glued on, but the original handle does interfere with it. The new handle does not work as well but it allowed for that sheet protector.

locker-box, plain wood, no parts in it, on table with door ajar

 The bare box with the door attached via 2 small door hinges.

close up on magnet in locker-box

A magnet helps the door close all the way with a satisfying snap. It also helps the door stay closed even though the door panel is slightly warped.

white 3D printed handle, about an inch long

The original door handle design. It is a 2 piece design with the curved section outside to grab on to and the smaller piece inside the door acting as a latch for the servo horn to block. The final revision ditched the outside section in favor of a simple finger notch.

Electronics 

All electronics components are housed in the front of the box. We only had 2 inches of space to work with since the shelf is only so deep and we wanted at least enough space in the lock box to place a letter size paper. We 3D modeled and 3D printed a electronics sled to hold major components like the Arduino Uno, lock servo, and breadboard. This way, we can mount and test components outside of the box and bolt the whole thing in when we are done testing. The modular design did prove helpful when assembling and debugging later on. 


The battery for the shelf in it is also mounted in the same space. It is an off the shelf battery box that takes AA batteries with a removable lid. We tested the power draw of the system and found that our shelf unit at 9V will last around 28 hours if left powered on. The office unit is plugged in to a socket all the time so there is no battery life considerations there.

The office unit is also much simpler in design because it only needed to have an Arduino Uno as a controller, wireless transceiver, LCD balance display while entering a new number, and a keypad. There wasn't much to mount as we just needed to make a simple box with cutouts for the keypad, display, and a hole for the power plug. This meant we just made a simple box on makercase.com, and imported it to SolidWorks to add the necessary coutouts.

Servo in place, other electronics around it visible but mostly out of frame. unlocked position.

A close up shot of the door lock and handle setup. There is a sanded finger notch for opening the door, and a small blocker piece inside the door where a servo could rotate to block when the box is locked.

locker-box with its front not on so you can get a clear view of the electronics. It's a lot of wire mess going on in there, and it is in fact a bit impressive we fit all that in there, trust me. We were working with maybe 2.5" depth.

The electronics bay inserted into the box. There is not much space to work with. Most of out components are mounted on one side, which is also removable from the rest of the box. Wires come out of it to connect to components on the front of the box.

its me :3 I'm on the computer.

Vincent debugging software on both units. The office unit can be seen closer to the camera and the shelf unit can be seen behind the computer. 

Manufacturing Difficulties

We had some troubles with manufacturing both the 3D printer parts and laser cut parts. The main Ideate laser cutter that we hoped to use was down during the last week of work, which made getting 3D printed parts really difficult. Fortunately there are plenty of other people at CMU who can 3D print stuff and we utilized other resources. The laser cuts were made of 1/8th inch plywood, which turned out to be slightly warped. This caused some small difficulties in assembly and major headaches when trying to make a door that closes flush. 


These difficulties were the main contributors to the team not following the original work plan. The days laid out for mounting electronics to the 3D printed sled came and went getting a printed piece. Our attempts at laser cutting was almost cut short by the laser cutting room monitor clocking out for the day (we were working really late into the night). But the code development mostly went according to schedule. 


Assembly and surface finishing also fell behind as there was difficulty planning out which components were available to be mounted and when. Due to this, the office unity was fully assembled and sanded by the day of presentations, while the locker unit was still held by tape until afterwards.


We also hadn't considered our need to access the Arduino after the box was fully assembled, so we ended up having to cut an access port by hand to finish out assembly and still be able to reprogram the fingerprint sensor.


The days set aside to complete this documentation page was also interfered with finishing up other projects, intense finals, and sudden travel plan changes for some team members.

Maeve sitting at a work bench assembling box parts. Photo is taken very sneaky

Maeve working on the laser cut pieces. Here is Maeve attaching the front piece of the shelf box. You can see the cutouts for components like the balance display and fingerprint sensor. You can also see the notched edges where the box pieces can intersect during assembly.

Conclusions and lessons learned 

Some of the feedback we received during the final crit presentation was very insightful. Someone mentioned that "I wish the battery pack could be accessed externally", which makes sense because the box would be locked without power if the battery runs out. This is very valid criticism for bad design. The lock box was an addition that was not in the original design. It could entirely not be locked and would probably work pretty well. However, to directly respond to this feedback here, it is possible to open the lock box without power by manually shifting the servo arm through the door handle notch. This is not good design and a failure on our part to only consider maximizing the paintable surface area on the outside of the box without thinking about the consequences of putting the battery compartment inside.

To expand upon this point about the box, someone else mentioned that it is "not clear locking box is needed, although nice addition. May need more thought". This pairs well with the previous feedback. In general, I think the box compartment was never designed well to begin with. It came about as a better use of space while the main goal is to fit the box in the shelf nicely and position the display at the front of the box. The storage compartment and locking ability was more of an afterthought that needed more time and iterations for improvement. 

If I were to do this project again with more time, I would prefer to go through the entire design process in its entirety, with iterations, user testing at multiple stages, and long term maintenance and support plans. The ideal path for developing this product would have been to create and validate a minimum viable product and place it in the actual shelf for testing. This would have the bare capabilities to turn on and receive a balance to display, without additional features like locking or storage. It would tell us the physical considerations we need to make and potentially allow for a pivot if the client does not like it. Then future iterations could modularly add in features like locking, accessible placements, and storage compartments, with a better understanding of how valuable each of those features are to the client.

On the other hand, people also loved the rest of our product. Multiple pieces of feedback mentioned that they "love that [Zajkora] has the ability to customize it", referring to the paintable surfaces. People also recognized our efforts in paying "such careful attention to their client's wants and needs" and how the device can help Zajkora have more independence. I think these are very valuable learnings to have and I am glad we were able to have this experience with Zajkora.

After out allotted interview with Zajkora, we ended up reaching out and having a second interview where we met with Zajkora alone. This was due to the fact that we believed having a member of staff present for the interview made it difficult to fully communicate with Zajkora, making it hard for us to explore ideas that weren't the concept already decided upon by Zajkora and the staff member before our meeting. Our second meeting ended up being helpful in its own right, as Zajkora seemed more comfortable to talk and discuss ideas with us without staff present, but at this point we still came away with the same design we had started with, just with some more specifics from Zajkora herself. In this case I believe we might have benefitted from our initial meeting being held alone, but we couldn't have known that this would be the case without the initial meeting taking place, so we can only assume what would be different.


On working with a client:

I am glad this is still an insightful project into being able to work with someone, without us being asked to design something life-changing towards someone's ability to function. From my read, Zajkora seemed happy to have us visit just to talk, and so I'm glad we visited CLASS a second time to meet with her. I think it is something a lot of folks take for granted that they're able to live in a situation where they can manage their schedule how they see fit and take more agency to change it when bored. I enjoy that some other projects for this class in previous semesters are simply fun pieces of art. Seeing products like this shows that there was a lot more insight into the "living" part rather than the "disability" part of "living with disability", which is probably a more useful takeaway than knowing how to manufacture an aerodynamic wheelchair (or whatever "designing for disability" could be assumed to mean from a less human level). I think our team did good with designing for the human (Zajkora).

I'm also glad this project broke us out of designing just for ourselves like in Project 2. Someone pointed out to me in the crit for that, that outcomes for that were similar enough that they could notice trends over time. "Staying hydrated" got trendy and there were water-intake trackers. "Take your meds" is getting trendy and you'll probably see more pill reminders. Alarm clock. So, I'm glad that we got to work with a client, because I have a feeling that designing for anyone (even without any disability, although, maybe they can't be part of the student-hive mind) produces a more varied or thoughtful device.

Group photo with Zajkora, with the device in frame on table

Technical Details

Block Diagram

blocks diagrammed.

Design Files

The design files of this project can be found here. This folder contains CAD files created in Solidworks or downloaded from GrabCAD Community. It also contains cut files exported as DXF and 3D objects exported as STL for 3D printing.

Locker unit/ Locker-box code:

// Balance Anytime - project by the Joey Chestnuts

// Code for the locker box. 4-dig 7-seg display, fingerptint sensor, servo lock-latch, & reciever end of wireless transciever.

// When boxUnlocked, asks for signal, displays it, moves servo.


#include <SPI.h>

#include <nRF24L01.h> // radio

#include <RF24.h> // radio again

#include "HT16K33.h"  // 7 seg

HT16K33 seg(0x70);  // 7-seg digit display i2c address


#include <DFRobot_ID809.h>  // vvv this chunk is all fingerprint

#include <SoftwareSerial.h>

SoftwareSerial Serial1(2, 3);  //RX, TX pins

#define FPSerial Serial1

#define COLLECT_NUMBER 3  //Fingerprint sampling times, can be set to 1-3, leave at 3

#define IRQ 6             //pin

DFRobot_ID809 fingerprint;


#include <Servo.h>

Servo servo;


RF24 radio(7, 8);                 // CE, CSN radio pins.

const byte address[6] = "42069";  // radio address - changeable but must match other radio. != 00001

float moneyFloat;                 // name of variable being recieved from transmitter

float prevMoneyFloat;

// 3.3v         gnd

// csn -> 8     ce -> 7

// mosi -> 11   sck -> 5

// irq ->       miso -> 12


void setup() {

  Serial.begin(9600);

  radio.begin();  // radio setup vvv

  radio.openReadingPipe(0, address);

  radio.setPALevel(RF24_PA_MIN);  // might need to be changed? don't know if this effects distance?

  radio.startListening();


  seg.begin();  // digit display setup vvv

  Wire.setClock(100000);

  seg.displayOff();

  seg.displayInt(8888);


  FPSerial.begin(115200);  // fingerprint setup vvv

  fingerprint.begin(FPSerial);

  while (fingerprint.isConnected() == false) {  //optional debug message

    Serial.println("Communication with fingerprint device failed, please check connection");

  }

  if (fingerprint.isConnected() == true) {

    Serial.println("fingerprint working");

  }

  servo.attach(5);  // servo pin

  servo.write(0);

  delay(10);

}


bool boxUnlocked = false;


void loop() {

  if (!digitalRead(IRQ)) {

    fingerprint.ctrlLED(fingerprint.eNormalClose, fingerprint.eLEDBlue, 0);

  } else if (digitalRead(IRQ) && boxUnlocked == false) {

    uint16_t i = 0;

    if ((fingerprint.collectionFingerprint(/*timeout=*/5)) != ERR_ID809) {   // idk

      fingerprint.ctrlLED(fingerprint.eFastBlink, fingerprint.eLEDBlue, 3);  // blue LED blinks quickly 3 times,

      while (fingerprint.detectFinger()) {

        delay(50);  // every 0.5seconds i ticks up.

        Serial.println(i);

        i++;

      }

      if (i == 0) {

      } else if (i > 0 && i < 15) {

        fingerprintMatching();  // call to check fingerprint library

      }

    }

  }

}

void boxUnlock() {

  Serial.println("box unlocked!");  // vvv aesthetic bits

  seg.displayOn();

  boxUnlocked = true;

  servo.write(90);  // moved it irl so this numb worked.

  delay(15);

  fingerprint.ctrlLED(fingerprint.eBreathing, fingerprint.eLEDMagenta, 0);

  if (!radio.available()) {                 // vvv radio happening

    Serial.println("radio not available");  // debug message here to happen once. otherwise leave {} empty

  }

  while (boxUnlocked == true) {                   // loop to stay in this func - only time we're

    prevMoneyFloat = moneyFloat;                  // constantly reading for the radio signal

    while (!radio.available()) {}                 // if no radio: do nothing.

    radio.read(&moneyFloat, sizeof(moneyFloat));  // reading variable from transmitter

    if (moneyFloat != prevMoneyFloat) {

      Serial.println(moneyFloat);

    }

    seg.displayFixedPoint2(moneyFloat);  // "fixedPoint" rather than "seg.displayFloat()" to keep decimal in same place. looks better.

    if (fingerprint.detectFinger() == true) {

      Serial.println(". . . locking!");

      fingerprint.ctrlLED(fingerprint.eFastBlink, fingerprint.eLEDYellow, 3);

      seg.displayOff();

      boxUnlocked = false;

      delay(2000);  // X seconds to take finger off

      servo.write(0);

      return;  // shoudln't ever go past here, returns to main loop thru fingerprintmatching.

    }

  }

}


void fingerprintMatching() {           // called on finger removed

  uint8_t ret = fingerprint.search();  // ret is "return on if fingerprint is in database"? =nonzero int

  if (ret != 0) {

    Serial.print("Successfully matched,ID=");

    Serial.println(ret);

    boxUnlock();

    return;  // comes back here once box relocked

  } else {

    fingerprint.ctrlLED(fingerprint.eKeepsOn, fingerprint.eLEDRed, 0);  // denied!!! = red

    Serial.println("Matching failed");

    delay(1000);

    fingerprint.ctrlLED(fingerprint.eNormalClose, fingerprint.eLEDBlue, 0);  // wait 1 sec, visually turns off

    Serial.println("-----------------------------");                         // then exits func

  }

}

Office unit/ Safe-box code:

// Balance Anytime - project by the Joey Chestnuts

// Code for the offic box. LDC screen, keypad, transmitter end of wireless transciever.

// transciever link we followed:

// https://howtomechatronics.com/tutorials/arduino/arduino-wireless-communication-nrf24l01-tutorial/

// use keypad to type things in. value updates & transmits.


#include <SPI.h

#include <nRF24L01.h>           // radio

#include <RF24.h>               // radio again

#include <Wire.h>               // ldc

#include <LiquidCrystal_I2C.h>  // ldc

#include <Keypad.h>             // keypad

#include <EEPROM.h>             // project deadline occurred right when i started testing this. May or may not work. fix if you dare.



LiquidCrystal_I2C lcd(0x27, 20, 4);  //lcd screen i2c address


const byte ROWS = 4;  // keypad initilization vvv (Maeve added this & all i know what this means is that it works lol)

const byte COLS = 3;  // so i haven't touched it.

char hexaKeys[ROWS][COLS] = {

  { '1', '2', '3' },

  { '4', '5', '6' },

  { '7', '8', '9' },

  { '*', '0', '#' }

};

byte rowPins[ROWS] = { 5, 4, 3, 2 };  // pinouts

byte colPins[COLS] = { A0, 9, 6 };    // pinouts, A0 used to be pin 10(?) but then pin 10 broke on our arduino.

Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);


RF24 radio(7, 8);                 // CE, CSN radio pins

const byte address[6] = "42069";  // radio address - changeable but must match other radio.


// moneyChar and moneyFloat are always the same value.

char moneyChar[] = "$__.__";        // char is what's printed on the lcd screen when entering new money value (different than float only for aesthetics)

float moneyFloat = 00.00;           // float is what's transmitted on radio.

bool numbLock = true;               // lock on the keypad so you can't accidentally enter numbers at wrong times. Doesn't apply to * or #

unsigned long timeOutCounter = 0;   // time out on the lcd screen (duration editable later in code)

unsigned long timeOutCounter2 = 0;  // time out on the lcd screen (duration editable later in code)

bool timedOut = false;              // goes with these timers ^^^


void welcomeScreen() {  // just calling this as it's own function because I call it in 3 different places.

  lcd.setCursor(0, 0);  // displays on startup and time out.

  lcd.print("# to check value");

  lcd.setCursor(0, 1);

  lcd.print("* to input value");

  numbLock = true;  // 95% sure this should not be called here because it makes you have to hit buttons twice sometimes

                    // but also like it's been long enough since I've worked on code I dont care to figure it all back out

}


void setup() {

  Serial.begin(9600);

  radio.begin();  // radio setup vvv

  radio.openWritingPipe(address);

  radio.setPALevel(RF24_PA_MIN);  // might need to be changed? don't know if this effects distance?

  radio.stopListening();

  lcd.init();  // lcd vvv

  lcd.noCursor();

  lcd.backlight();

  lcd.setCursor(0, 0);

  lcd.print("Hello!");  // just to be polite

  delay(1000);

  welcomeScreen();

}

void loop() {


  char customKey = customKeypad.getKey();  // always waiting for keypad to be hit.

  if (customKey) {                         // if a key has been hit ...

    timeOutCounter = millis();

    if (timedOut == true) {  // vvv if screen was timed out, go back to welcome

      lcd.backlight();

      lcd.display();

      welcomeScreen();

      timedOut = false;                                  // ^^^ done. waiting for keypress.

    } else if (customKey == '#' && timedOut == false) {  // displays moneyFloat on lcd screen

      numbLock = true;                                   // so you can check current value from office safe-box.

      lcd.clear();

      lcd.noBlink();  // cursor stuff is just for aesthetics

      lcd.noCursor();

      lcd.setCursor(0, 0);

      lcd.print("You have:");

      lcd.setCursor(0, 1);

      lcd.print("$");  // prints float instead of char so the decimal is in a pretty place

      lcd.setCursor(1, 1);

      lcd.print(moneyFloat);

    } else if (customKey == '*' && timedOut == false) {  // used to reset and enter new value

      moneyFloat = 00.00;                                // vvv resets both money values to 0

      moneyChar[0] = '$';

      for (int i = 1; i < 6; i++) {

        moneyChar[i] = '_';

      }

      moneyChar[3] = '.';  // ^^^ done resetting values. vvv lcd printing some text

      lcd.clear();

      lcd.setCursor(0, 0);

      lcd.print("Enter new value:");

      lcd.setCursor(0, 1);

      lcd.print(moneyChar);

      lcd.setCursor(1, 1);

      lcd.blink();

      numbLock = false;  // it's ready for you to enter a new value.

    }                    // note- while unlocked, moneyChar and moneyFloat are updated (so, saved) upon any key that is a digit being pressed

                         // so screen timing-out, or hitting * or # while numbLock = false is fine, and doesn't lose the value just entered.

                         // the rest of the digits will be saved as '0's.


    if (numbLock == false && isdigit(customKey)) {  // vvv these statements are for filling out moneyChar and moneyFloat

      if (moneyChar[1] == '_') {                    // checking the list for the first empty spot for a digit...

        EEPROM.write(0, customKey);

        moneyChar[1] = customKey;              // [1] is the 10s digit place. Entering a '0' here is fine.

        moneyFloat += (customKey - '0') * 10;  // update float at same time to match

        lcd.setCursor(0, 1);                   // prints the new value on screen

        lcd.print(moneyChar);

        lcd.setCursor(2, 1);  // cursor is blinking in the next open '_' spot now. For legibility + aesthetics

      } else if (moneyChar[2] == '_') {

        EEPROM.write(1, customKey);

        moneyChar[2] = customKey;

        moneyFloat += (customKey - '0');

        lcd.setCursor(0, 1);

        lcd.print(moneyChar);

        lcd.setCursor(4, 1);

      } else if (moneyChar[4] == '_') {

        EEPROM.write(2, customKey);

        moneyChar[4] = customKey;

        moneyFloat += (customKey - '0') * 0.1;

        lcd.setCursor(0, 1);

        lcd.print(moneyChar);

        lcd.setCursor(5, 1);

      } else if (moneyChar[5] == '_') {  // this is the last digit in the 0.01s place.

        EEPROM.update(3, customKey);


        moneyChar[5] = customKey;


        moneyFloat += (customKey - '0') * 0.01;

        lcd.clear();

        lcd.noBlink();

        lcd.noCursor();

        lcd.setCursor(0, 1);

        lcd.print(moneyChar);

        lcd.setCursor(0, 0);

        lcd.print("Value saved.");  // it was already saved, this is just for UI.

        numbLock = true;

      }

    }


    Serial.print(moneyFloat);  // serial prints just for testing. removable.

    Serial.print(", ");

    Serial.print(moneyChar);

    Serial.print(", ");

    Serial.print(EEPROM.read(0));

    Serial.print(",");

    Serial.print(EEPROM.read(1));

    Serial.print(",");

    Serial.print(EEPROM.read(2));

    Serial.print(",");

    Serial.print(EEPROM.read(3));

    Serial.println(",");



  }  // end of statements for 'if any key is pressed'.


  if (millis() - timeOutCounter > 3000 && millis() - timeOutCounter < 6000 && !timedOut) {  // delays are short for testing. this one happens first- back to welcome screen.

    timedOut = true;

    numbLock = true;

    welcomeScreen();

  }

  if (millis() - timeOutCounter > 6000) {  // 2nd time out delay - screen goes off. EEPROM save

    lcd.noDisplay();

    lcd.noBacklight();

    timedOut = true;

    numbLock = true;

  }

  radio.write(&moneyFloat, sizeof(moneyFloat));  // on every loop the new value is sent- so constantly. this might not have to be true.

}