Introduction: Rotary Phone Dial + Arduino + Invisible Ink = Birthday Present

About: Retired Math teacher who needs a hobby! So I tinker with stuff: Arduino, welding, my 1958 TR-3 , my tennis serve
I have a number of rotary dial phones and phone parts which I thought I could use in some silly way. 

I starting with this instructable  https://www.instructables.com/id/Interface-a-rotary-phone-dial-to-an-Arduino/  

 When I finished, I have a item which works as follows:

- dial any number or sequence of numbers
- press the big red button to test that sequence.
- the arduino will play a song based on the first digit of the sequence dialed.
- But if the correct sequence is dialed, in this case my daughters name, the arduino will play the "Happy Birthday song" , spin the metal screen and light the UV leds. This will reveal the "Happy Birthday message I wrote on the screen with the invisible ink pen.


video to follow   




So basically what I have is:

The Arduino records the rotary phone input as a string and then the code checks for a particular string.

If it is not that string, it then plays one of 5 songs that are encoded in the sketch.

If it is the correct string then the arduino instructs the servo to turn and lights the UV lights and plays the birthday song.



The code follows:

I found pieces of it here and there. The tone function is used along with a pitches.h file.  

/*  3/21/12 - started to make project with rotary dial
- to be used for birthday present for Christine
- idea:
dialing numbers will play a different song
dialing her name will light LEDs which will show the Happy birthday messgae
or the Happy aniversity for Harrie and Riek

- starting with the code for the batphonev1
- need to make many changes

-v2 - begin looking at watys to have many songs or notes



*/
#include <Servo.h>
#include "pitches.h"


// happy birthday
  int melodybd[] = {NOTE_C4,NOTE_C4,NOTE_D4,NOTE_C4,NOTE_F4,NOTE_E4,NOTE_C4,NOTE_C4,
NOTE_D4,NOTE_C4,NOTE_G4,NOTE_F4,NOTE_C4,NOTE_C4,
NOTE_C5,NOTE_A4,NOTE_F4,NOTE_E4,NOTE_D4,NOTE_B4,NOTE_B4,NOTE_A4,
NOTE_F4,NOTE_G4,NOTE_F4  };
   int noteDurationsbd[] = { 3, 16, 4, 4, 4, 2, 3, 16, 4, 4, 4,2, 3, 16, 4,4,4,4,4,3,16,4,4,4,2};
   int numNotesbd = 25;




// aniversary
//   here comes the bride
int melodyanv[]= {NOTE_A3,NOTE_C4,NOTE_C4,NOTE_C4,NOTE_A3,NOTE_D4,NOTE_B3,NOTE_C4,NOTE_A3,NOTE_C4,NOTE_F4,NOTE_F4,NOTE_E4,NOTE_D4,NOTE_C4,NOTE_B3,NOTE_C4,NOTE_D4 };
// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurationsanv[]= {2,3,8,1,2,3,8,1,2,3,8,2,3,8,2,3,8,1  };
int numNotesanv = 18;



// 1,starwars
int melody1[] = { NOTE_G5, NOTE_G5, NOTE_G5, NOTE_DS5, NOTE_AS5, NOTE_G5, NOTE_DS5, NOTE_AS5, NOTE_G5};
int noteDurations1[] = { 3, 3, 3, 4, 8, 3, 4, 8, 2 };
int numNotes1 = 9;






   //   2. two bits thing
    int melody2[] = {  NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4};
    int noteDurations2[] = { 4,8,8, 4,4,4,4,4};
     int numNotes2 = 8;


//3 pop goes the weasel

int melody3[] = {
   NOTE_C4, NOTE_C4, NOTE_D4, NOTE_D4, NOTE_E4,
   NOTE_G4, NOTE_E4, NOTE_C4, NOTE_C4, NOTE_C4,
   NOTE_D4, NOTE_D4, NOTE_D4, NOTE_E4, NOTE_C4, 0,
   NOTE_C4, NOTE_C4, NOTE_D4, NOTE_D4, NOTE_E4,
   NOTE_G4, NOTE_E4, NOTE_C4, 0, NOTE_A4,
   NOTE_D4, NOTE_F4, NOTE_E4, NOTE_C4, 0};

    int noteDurations3[] = {4, 8, 4, 8, 8, 8, 8, 4, 8, 4, 8, 4, 8, 3, 4, 8, 4, 8, 4, 8, 8, 8, 8, 4, 4, 2, 4, 4, 4, 4, 4};
int numNotes3 = 31;


// 4 batman
  int melody4[] = {  NOTE_A3, NOTE_A3, NOTE_GS3, NOTE_GS3, NOTE_G3, NOTE_G3, NOTE_GS3, NOTE_GS3, NOTE_A3, NOTE_A3, NOTE_GS3, NOTE_GS3, NOTE_G3, NOTE_G3,NOTE_GS3, NOTE_GS3, NOTE_A3, NOTE_A3, NOTE_GS3, NOTE_GS3, NOTE_G3, NOTE_G3, NOTE_GS3, NOTE_GS3, NOTE_A3, NOTE_A3, NOTE_GS3, NOTE_GS3, NOTE_G3, NOTE_G3,NOTE_GS3, NOTE_GS3, NOTE_E4, NOTE_E4};
int noteDurations4[] = { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4,8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4 };
int numNotes4  = 32;


// 5  familar classical
int melody5[]= {NOTE_E4,NOTE_E4,NOTE_F4,NOTE_G4,NOTE_G4,NOTE_F4,NOTE_E4,NOTE_D4,NOTE_C4,NOTE_C4,NOTE_D4,NOTE_E4,NOTE_E4,NOTE_D4,NOTE_D4,NOTE_E4,NOTE_E4,NOTE_F4,NOTE_G4,NOTE_G4,NOTE_F4,NOTE_E4,NOTE_D4,NOTE_C4,NOTE_C4,NOTE_D4,NOTE_E4,NOTE_D4,NOTE_C4,NOTE_C4,NOTE_D4,NOTE_D4,NOTE_E4,NOTE_C4,NOTE_D4,NOTE_E4,NOTE_F4,NOTE_E4,NOTE_C4,NOTE_D4,NOTE_E4,NOTE_F4,NOTE_E4,NOTE_D4,NOTE_C4,NOTE_D4,NOTE_G3,NOTE_E4,NOTE_E4,NOTE_F4,NOTE_G4,NOTE_G4,NOTE_F4,NOTE_E4,NOTE_D4,NOTE_C4,NOTE_C4,NOTE_D4,NOTE_E4,NOTE_D4,NOTE_C4,NOTE_C4};
// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations5[]= { 4,4,4,4,4,4,4,4,4,4,4,4,2,8,2,4,4,4,4,4,4,4,4,4,4,4,4,2, 4,4,4,4,4,8,8,4,4,4,8,8,4,4,4,4,2,4,4,4,4,4,4,4,4,4,4,4,4,2,8,2 };
int numNotes5 = 62;





int needToPrint = 0;
int count;
// mine
const int try_it = 3;
const int in_from_dial = 2;
const int lightOn = 11;

int buttonState = 0;         // variable for reading the pushbutton status
int firstnum = 0;
char played = 'N';
// end mine


int lastState = LOW;
int trueState = LOW;
long lastStateChangeTime = 0;
int cleared = 0;

// constants

int dialHasFinishedRotatingAfterMs = 100;
int debounceDelay = 10;

// strings
String newstring;
  char Carrie [ ] =  "227743" ;
  char Daniel  [ ] =  "326435" ;
//  char Big50[ ] =  "1" ;
// char Harrie[ ] =  "2" ;


// servo
Servo myservo;  // create servo object to control a servo
int pos = 0;    // variable to store the servo position

// --------------------------------------------


void setup()
{

Serial.begin(9600);


pinMode(in_from_dial, INPUT);  // 2
pinMode(try_it, INPUT);  // 3
pinMode(lightOn, OUTPUT);    // 11
pinMode(13, OUTPUT);    // 12
myservo.attach(6);  // attaches the servo on pin 6 to the servo object

}


void loop(){
  digitalWrite(13, HIGH);   // set the LED on
/*
user will dial numbers until they hit the "try it" buttonb
so need to create string until button is pressed
*/
// read the state of the tryit button
digitalWrite(lightOn, LOW);
  buttonState = digitalRead(try_it);
// try_it = HIGH;
if (buttonState == LOW)   {

int reading = digitalRead(in_from_dial);

if ((millis() - lastStateChangeTime) > dialHasFinishedRotatingAfterMs) {
// the dial isn't being dialed, or has just finished being dialed.
if (needToPrint) {
// if it's only just finished being dialed, we need to send the number down the serial
// line and reset the count. We mod the count by 10 because '0' will send 10 pulses.
  Serial.println(count % 10, DEC);

// now need to add the count to the test string and then test it against the
// required string to get a hit
newstring.concat(count);


needToPrint = 0;
count = 0;
cleared = 0;
}



}

if (reading != lastState) {
lastStateChangeTime = millis();
}
if ((millis() - lastStateChangeTime) > debounceDelay) {
// debounce - this happens once it's stablized
if (reading != trueState) {
// this means that the switch has either just gone from closed->open or vice versa.
trueState = reading;
if (trueState == HIGH) {
// increment the count of pulses if it's gone high.
count++;
needToPrint = 1; // we'll need to print this number (once the dial has finished rotating)
}
}
}
lastState = reading;
}

else
{
// now user wants to test his dialing
//
played = 'N';
//   Serial.println(newstring);
  test_it();
   newstring = "";

}
}
// --------------------- my functions -------------------------
// ------------------------------------------------------------

// turn on leds

void turnon_Leds()
{
  digitalWrite(lightOn, HIGH);





// --------------------------------------------------
// test the string

void test_it()
{


//  Serial.println(newstring);
//Serial.println(firstnum);
// delay(2000);

  /*


if "BIG50" then play Happy Birthday,turn servo , turn on Leds
if "HARRIE" then play anv   song, trun servo turn on leds

*/
if (newstring.equals(Carrie)) {

   // turn servo
    for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees
  {                                  // in steps of 1 degree
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }

    turnon_Leds();

  for (int thisNote = 0; thisNote < numNotesbd; thisNote++) {

    int noteDuration = 1000/noteDurationsbd[thisNote];

    tone(8, melodybd[thisNote],noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 1.4;
    delay(pauseBetweenNotes);
    // stop the tone playing:

    noTone(8);
  }
   played = 'Y';
   delay(2000);

}




//-----------------------------------------

if (newstring.equals(Daniel)) {

   // turn servo
    for(pos = 180; pos >=15; pos -= 1)  // goes from 0 degrees to 180 degrees
  {                                  // in steps of 1 degree
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }


   turnon_Leds();

  for (int thisNote = 0; thisNote < numNotesbd; thisNote++) {

    int noteDuration = 1000/noteDurationsbd[thisNote];

    tone(8, melodybd[thisNote],noteDuration);

    int pauseBetweenNotes = noteDuration * 1.4;
    delay(pauseBetweenNotes);
    // stop the tone playing:
        noTone(8);
  }
  played = 'Y';
//  newstring  = "";
delay(2000);
}

//   Serial.println("got here1"); 
//  delay(500);

// need first difgit and then use case to play the song


// Serial.println("here2");
// Serial.println(newstring);
// delay(1000);

if (played == 'N') {

   // 1 0or 9
if ((newstring.startsWith("1")) || (newstring.startsWith("9") ) ) {

   // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < numNotes1; thisNote++) {
    int noteDuration = 1000/noteDurations1[thisNote];
    tone(8, melody1[thisNote],noteDuration);

    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(8);

}
played = 'Y';
delay(500);
//   newstring  = "";
}


// starts with 2 or 8
if ((newstring.startsWith("2")) || (newstring.startsWith("8") ) )
   {

   // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < numNotes2; thisNote++) {
    int noteDuration = 1000/noteDurations2[thisNote];
   tone(8, melody2[thisNote],noteDuration);


    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(8);

}
played = 'Y';
delay(500);
//  newstring  = "";
}



// starts with 3 or 7
if ((newstring.startsWith("3")) || (newstring.startsWith("7") ) )
  {

   // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < numNotes3; thisNote++) {
    int noteDuration = 1000/noteDurations3[thisNote];
   tone(8, melody3[thisNote],noteDuration);


    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(8);

}
played = 'Y';
  delay(500);
}




// starts with4 or 6
if ((newstring.startsWith("4")) || (newstring.startsWith("6") ) )
   {

   // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < numNotes4; thisNote++) {
    int noteDuration = 1000/noteDurations4[thisNote];
    tone(8, melody4[thisNote],noteDuration);

    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(8);

}
played = 'Y';
delay(500);

}



// starts with 5 or 0
if ((newstring.startsWith("5")) || (newstring.startsWith("0") ) )
   {

   // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < numNotes5; thisNote++) {
    int noteDuration = 1000/noteDurations5[thisNote];
   tone(8, melody5[thisNote],noteDuration);

    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(8);

}
played = 'Y';
delay(500);

}




}


// end of loop
}


Arduino Challenge

Participated in the
Arduino Challenge