Advent House - Telling Stories..

by Haelge in Circuits > Arduino

151 Views, 1 Favorites, 0 Comments

Advent House - Telling Stories..

Kindermit Adventsladen2.jpg
Adventsladen.jpg

Children love stories. Grandfathers love children who like to listen to stories.

But most grandfathers can't visit the children every day to read aloud...

Children love Advent calendars. Every day a little window with a surprise, from December 1st to December 24.

But if there is only one piece of chocolate in the calendar while there are five children, there will be arguments.

Not very "Christmassy".

We need an Advent calendar that offers something for all children at the same time. For example, a passage of a beautiful Christmas story every day in December until Christmas Eve. The story will become even more beautiful if grandpa reads it aloud and there are pretty illustrations to go with it. Well...

I came up with the idea of building an "Advent house" in which the story is hidden along with pictures and grandpa's voice.

But the whole thing was not as easy as I had hoped. I felt very much like old Petterson with his "Santa Claus machine".

The story I wanted to read. ( "ISBN 978-3-7891-4307-6 " by Sven Nordqvist)

Again and again new problems arose and the time until December was getting shorter and shorter. No sooner was one problem solved than a new difficulty arose. For example, when I realized that a small Arduino Nano doesn't have enough program memory to include all the project elements... And the book also had to be read aloud, which took a lot of time to create the necessary audio files for the many sections. The Advent house was not finished until around noon on 1 December. It worked! A Christmas miracle like in the Findus story!

So please forgive me if some parts of the Project are still a bit messy, especially the code.

Supplies

bauteilesammlung.JPG

To make things a little easier for the coming Advent, here are some building instructions:

Supplies:

for the house model:

  • Plywood 3mm
  • Acrylic paints for painting
  • transparent foil or tracing paper for windows
  • Drawing board dark brown or black for the window frames
  • Wood glue and other suitable adhesive (e.g. hot melt glue)
  • Drawing of the house components (I attached a PDF, but you may alter it as you like)

Electronics:

  • 1 6.5V power supply with at least 500 mA
  • 2 Arduino Nano (just because one Nano does not supply enough program memory)
  • 1 DF MP3 Player mini
  • 1 TFT display with SD card slot, 1.8" 160x128 pix
  • 1 RTC1302 board with backup battery
  • 2 matching SD cards
  • 5 LEDs warm white 5mm
  • 5 series resistors 560 Ohm for the LEDs
  • 1 resistor 10K as pull-up for display reset
  • 1 small speaker
  • 1 micro probe or similar pushbutton
  • Socket headers for the MCs (easier programming outside the house...) and modules
  • Perfboard for mounting and wiring the components
  • Wire connections (stranded wire 0.25mm²)
  • Soldering Accessories

I attached a KICAD schematic for the circuits (step 2)...

  • scanner or camera to get the images to illustrate the story
  • imaging software like GIMP to process the images so they can be displayed on the little TFT screen
  • PC with Arduino IDE and the necessary libraries
  • Audio software (e.g. Audacity) and a microphone to process your readings

Build the House Model

Cut out ground plane , walls and roof from plywood 3mm. I used a laser to do this but you can use a scroll saw as well. Or, if you prefer, cut the parts from cardboard with knive and scissors.

Paint walls and roof to your liking. I used yellow for the walls and red for the roof.

Next, cut the window panes from transparent material and glue the sheets to the walls from the inside except at the shop window, there you will mount the TFT screen later on.

Cut the window frames from cardboard and glue them at the outside. This will make the model more realistic.

Then mount the walls onto the ground sheet. The little lantern beneath the shop needs a small hole in the wall where one of the LEDs will be mounted to light the lantern.

The roof has to wait until all the electric parts are inside the house and the circuits and code is tested.

I did not glue the roof to the rest of the house in case I had to get to the electronics once more or to change the code and media in this years Advent, to tell another story... I attached some pieces of plywood to the roof so that I can put it onto the walls without glue.

Downloads

Electronics

schematic.png
P1030605.JPG
buchsenreihe.JPG
buchsenreiheMitArdu.JPG

First cut out a piece of perfboard to fit into the house model.

Next attach a row of socket headers to each side of the Arduino-pins and put them onto the perfboard in a position where you can easily solder the wires later on. When you are satisfied with the position you start soldering the socket headers starting at the end point of each row. Make a sketch of the orientation of the NANOs and their GPIOs and paint a number (1 / 2) onto the MCs to better remember the positions and not confuse MCs, pins and the code. After this you can remove the Arduino Nano boards and begin soldering the rest of the headers and the wire connections following the schematic.

I fitted the LEDs with resistors 560R . We do not want too much current at the LEDs. Also I used small connectors so that I could remove the circuit board even after the LEDs were glued in place at the walls.

LED 5 is for the Lantern outside. You will have to glue it next to the little hole in the wall behind the lantern. The other four LEDs are mounted at the back wall of the house model so that they are lit up from top to bottom when the program starts. Take a look at the code to see this function or just make a test run before gluing the LEDs. I wanted the illusion of Pettersson waking up in his Room under the roof, coming down the stairs and entering the shop to tell the story...)

When you solder the wires to the TFT, take care that there is enough wire to mount the little screen at the shop window.

The pushbutton is mounted beneath the door, as a "doorbell". It is used do start the sequence of the day as often as you want. My grandchildren used to start most sequences more than once...

Make sure the reset pin of the Display is pulled up to 5V by a 10K Resistor. Otherwise you will experience a random screen reset and then you will have to restart the whole machine. This was one of the problems I had while testing the code...

DC Power (min 5V to max 7.5V) is connected to the VIN pins of the Arduinos as shown in the schematic.

When all the wires are properly soldered and connected to the peripherals (MP3Player, RTC, Display, SD-Reader, speaker, LEDs) you are ready to make a test run after flashing the code and loading some media snippets...



Preparing Media

passageDivider.png
115.bmp

Before you adapt the code to your needs, you will need all the pictures you want to show and all the soundfiles.

Divide your text into separate passages (see example text) and give a number for the start of each.. This number isused for the soundfile (with padding zeroes.. --> 0001.mp3) and for the corresponding images (---> 1.bmp)

Images:

To display Images on such a small TFT with the <Adafruit_ST7735.h> library you have to convert all the images to raw .bmp format without header tags and - very important- remove the alpha transparency layer. Crop and scale the images to 160x128 pix. It is good to raise contrast a little for such low resolution images, See the example image I attached here.

For these operations I used GIMP, but you may use any good imaging software you have available.

Then name the files in the order of the passages (1.bmp, 2.bmp ...... x.bmp ) depending on the number of passages in your soundfiles. Always one passage soundfile and one corresponding image file with the same number...

Copy them to the SD-card for the TFT-display at NODE 2.

Soundfiles:

To get good recordings you may use a program like Audacity. There you find a function called "normalize" and another called "compressor" The normalize function brings your recordings to a consistent volume, which is very important. You do not want large fluctuations in volume. Next use "noise reduction". Often the compressor function is helpful ,too. Equalizer or bass/treble filter functions can improve the sound Quality. For special effects I used timestretching and change of pitch. In the end you should get a soundfile with clear voice at a constant volume. Then reduce it to mono and encode it to MP3 format. Collect all your soundfiles in a separate folder and name them in the order of your passages from 0001.mp3 to 0xxx.mp3.

Now that's a bit tricky: the DFRobotMP3mini Player can´t read filenames as usual!

the "play file" command takes the soundfiles depending on the order they are stored on the SD card!

So if you store 0001.mp3 after you stored 0002.mp3, the file that will play on the command "play 1" will be 0002.mp3!

First I copied the whole bunch of files to the SD and found out that on playing the numbers were reversed...

I had to save one file after the other beginnng with 0001 up to 0126....

To test your SD-sound collection you may use some code like "ganzeGeschichte.ino". This code will play all the soundfiles beginning at file 1 up to 126. If the order of your soundfiles is ok, you may use the SD card in our project.


Coding

Now it is time to prepare the code for the Arduino Nano Boards.

As we have two Nanos in this project, each of them has its separate code (I mentioned above why I used two of them - to have more program memory space. If you change the code to use another MCU with more memory space you might need only one mcu e.g.an STM32F or an ESP32 but I already had some Nanos and didn't want to buy a new MCU...) .

I recommend to mark the Nano-Boards with number 1 and 2 in order not to confuse them when you are coding or inserting them into the circuit later.

The first Nano will become NODE 1. This MCU handles the control of the MP3 Player, reads the RTC and decides which text and picture can be displayed during the current day. It will be connected to the other (NODE 2) by an I2C bus. NODE 2 handles the TFT and the SD-Reader for all the pictures and gets its command variables over I2C from Node 1.

If you look at my code you will find a function called "compose()" on Node1. This is the one you will have to edit in order to display your own story and pictures.

Here I will show where to look at:

 switch (tag) { ("tag" is the current day, this variable is read from the RTC)

     case 1: (as we only tell the story in December, this is the 1st of December...)

       // abschnitt 1 (abschnitt is German for a passage in your text, this is the first passage...)

       bild = 1; (bild is the variable of the picture to display, here number 1...)

       ton = 1; (ton is the variable for the MP3 file to play, here number 1...)

       zeige = 1; // (this variable is transferred by I2C to NODE 2 and commands the Display of - in this case- 1.bmp)

       event = 1; (variables I use to control NODE 2...)

       event2 = 1; (variables I use to control NODE 2...)

       senden = true; (variables I use to control NODE 2...)

°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°

Here I insert some Code from NODE 2 to explain how these I2C variables are used :

//°°°°°°°°°°°°°

//Bildwechsel und Tonausgabe (This is the function that handles the output...)


void aus() {


 if (zeige == 1) { ("zeige" is the variable that starts or stops the display of a picture)

   Serial.println(F("VoidAusgabe")); (a debug line, not necessary...)

   Serial.println(zeige); (a debug line, not necessary...)

   while (zeige == 0)

     ; //warten bis zeige auf 1 geht... (wait until "zeige" changes to HIGH)

   //Dateiname für aktuelles Bild auf SD zusammensetzen: ( Compose the correct filename of the .bmp)

   String zwei = bild + ".bmp"; (this step is crucial, as the TFT library expects a char, not a String ! )

   Serial.print("Bild:"); (a debug line, not necessary...)

   Serial.println(zwei); (a debug line, not necessary...)


   // Umwandlung String to char* (erforderlich weil Bild sonst nicht angezeigt wird)

   const char *filename = zwei.c_str(); (Here I convert a pointer to a constant char. Only way I found to do this..)

   if (event2==2){  //Wartebildanzeigen wenn event2=2

(if no picture is ordered by Node 1, "event2" variable is set to 2 and a fixed picture "200.bmp" is shown)

 filename="200.bmp";

}

   // Display bitmap (Now the picture will be sent to the screen....)


   tft.fillScreen(ST7735_BLUE); (you may alter this color to your liking...)

   reader.drawBMP(filename, tft, 0, 0); // Bild anzeigen auf Display

    stat = reader.drawBMP(filename, tft, 0, 0); (a debug line...)

  reader.printStatus(stat); // Kontrollfunktion.. (a debug line...)

   zeige = 0;                           //blockiert weitere anzeige bis zum nächsten Datenempfang

(if "zeige" is set LOW, NODE 2 waits until new Data come over I2C...)

 }

}

//°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°

Now back to NODE 1:


       formatieren(); (calls the function that sends DATA over I2C to NODE 2 ...)

       zeige = 0;

       myMP3.play(ton); //Tonausgabe( Nummer der MP3-Datei...) (starts playing the MP3 file...)

       delay(1000);

       while (myMP3.isPlaying())

         ; // warten bis zu Ende abgespielt (waits until the MP3 file stops...)

       delay(2000);

(END of passage 1)

( The following lines prepare the output of the second passage just like passage 1...)

       //abschnitt 2

       bild = 2;

       ton = 2;

       zeige = 1; //Freigabevariable für Bildanzeige

       event = 1;

       event2 = 1;

       senden = true;

       formatieren();

       zeige = 0;

       myMP3.play(ton); //Tonausgabe( Nummer der MP3-Datei...)

       delay(1000);

       while (myMP3.isPlaying())

         ; // warten bis zu Ende abgespielt

       delay(2000);

---------------------------------------------------------------------------------------------

Last I will show the part of code that starts the show if you push the button at the door:

vaiable "k" will go LOW, and then the following function is called:

°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°

void starten() {

 digitalWrite(6, LOW);

 Serial.println("Startsequenz");

 Serial.println("Aschenbrödel");

 myMP3.play(112); (plays a tune to announce the show...)

 delay(1000);

 while (myMP3.isPlaying())

   ; // warten bis zu Ende abgespielt


(now the LEDs light up...)


 digitalWrite(2, LOW); // Lichter nacheinander einschalten (top LED...)

 delay(1000);

 digitalWrite(3, LOW); (LED a bit further down...)

 delay(1000);

 digitalWrite(4, LOW); (basement LED....)

 delay(1000);

 digitalWrite(5, LOW); (Lantern LED..)


 Serial.println("Start Tagesprogramm"); (debug Info...)

 compose(); (function call to compose display and sound....)

 k = 1; (reset the variable of pushbutton...)

}

°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°

I hope you can see how the code works and which parts you will have to change for your own version.

My version is for 112 passages and pictures...

You will find lots of instructions on the web how to use the Arduino IDE and send code to an Arduino Nano (or Uno), so I need not describe all the steps here.

As we have two Nanos in this project, each of them has its separate code (I mentioned above why I used two of them - to have more program memory space. If you change the code to use other mcu with more memory space you might need only one mcu e.g.an STM32F or an ESP32 but I already had some Nanos and didn't want to buy a new MCU...) .

I recommend to mark the Nano-Boards with number 1 and 2 in order not to confuse them when you are coding or inserting them into the circuit later.


Testing

Kindermit Adventsladen2.jpg

Now you may need to test the whole show.

Set the RTC to a date between December 1st and December 24 and try if sound ant Images for this day are performed as you planned.. If so, set the RTC to the actual date and time (use the outcommented code in NODE1:  //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));) reflash the code and insert your MCU NODE 1 into the circuit.

Then you can present the machine to your grandchildren or someone else you like.


Have fun!