ISOPOD - Upcycled MP3 Player Tamagotchi Belt Attachment

by STENTOR in Circuits > Wearables

97 Views, 1 Favorites, 0 Comments

ISOPOD - Upcycled MP3 Player Tamagotchi Belt Attachment

MP3 Player(1).jpg
full isopod video

This project—ISOPOD—is a wearable MP3 player and Tamagotchi-style belt attachment built using an Arduino Nano, DFPlayer Mini, and a small OLED screen. Everything is housed in a handmade case. The audio plays through upcycled Bluetooth headphones/retro intercom system phone, rewired for a direct connection to the player.

The goal was to create something fun, portable, and sustainable, using mostly reused parts.

The Tamagotchi style game is shown after double-clicking the middle button to activate an isopod pet that dances to the music and sleeps when its paused - using animated bitmaps!

Supplies

Screenshot 2025-04-30 154503.png

Electronics:

  1. Double Side Protoboard 4*6
  2. Arduino Nano
  3. DFPlayer Mini MP3 Module
  4. Micro SD card
  5. 1.3" OLED Display
  6. push buttons (x3)
  7. LiPo battery with charging circuit
  8. Boost Converter 3.7 from lipo to 5v
  9. Jumper wires
  10. Broken over-ear headphones

Tools:

  1. Soldering Iron
  2. Solder
  3. Multimeter for testing
  4. Breadboard for prototyping and testing

Utility Belt:

  1. Small metal hooks and clips for belt attachment
  2. Cardboard and duck tape to create container
  3. Denim (old clothes to cut it from) and sewing machine/needle and thread

Mp3 Player Functionality

Screenshot 2025-04-30 155301.png

Start by connecting the DFPlayer Mini to the Arduino Nano on a breadboard.

DFPlayer Docs

Wiring:

DFPlayer Mini → Arduino Nano
VCC → 5V
GND → GND
TX → D10 (via 1kΩ resistor)
RX → D9

Connect an external speaker (8Ω, 2W) to the DFPlayer:

SPK_1 (+) → Speaker +
SPK_2 (-) → Speaker -

Upload your music files to the micro SD card and insert it into the DFPlayer.

Then upload a basic test script (attached below) using the Arduino IDE to check that everything works. The DFPlayer’s onboard LED should light up when music is playing.

Connect Display and Inputs

display-dfplayer-inputs.jpg
MP3 Player.png

OLED Display (1.3", I2C)

Next, wire up the OLED screen and the control buttons.

OLED → Arduino Nano
VCC → 5V
GND → GND
SCK → A5
SDA → A4

Push Buttons

Connect the buttons to digital pins (D2, D3, D4) and ground, using pull-down resistors if necessary. These will serve as inputs for Play/Pause, Next, and Previous controls.

The button controls will be:

  1. Left Button:
  2. Single click = Previous track
  3. Long press = Volume up
  4. Middle Button:
  5. Single click = Play/Pause
  6. Double click = Enter game mode
  7. Right Button:
  8. Single click = Next track
  9. Long press = Volume down

Power

MP3 Player (3).jpg

To make this project portable, I will be adding a 3.7V Lipo battery, however ardunio nanos would require around over 5V so ill connect a 3.7v to 5v boost converter. Then a usb-c charging module so that it can be easily recharged - with over charge & discharge protection (This is vital to protect the circuit and battery).

[ LiPo Battery 3.7V ]
├── (Red) + → B+ on TP4056
└── (Black) - → B- on TP4056

[ Charger Board ]
├── (Out+) → IN+ on Boost Converter
└── (Out-) → IN- on Boost Converter

[ Boost Converter ]
├── (OUT+) → 5V pin on Arduino Nano
└── (OUT-) → GND pin on Arduino Nano

Connect Everything

back.jpg
module.jpg
MP3 Player.jpg

To then connect everything together, from the breadboard to a permanent circuit board, place the Arduino nano, DFPlayer 1K resistor and buttons onto the perforated circuit board and move around the location until it all fits (the display will go over the DFPlayer due to the limited space).

Fold over or remove the pins on the Arduino nano and DFPlayer that will not be used to make it process more clear. Then solder the 3 buttons into place and the Arduino above the buttons, add a Ground rail with a jumper wire along the bottom of the circuit direct to the ground pin on the Arduino to connect all the buttons to.

Then place the DFPlayer above the Arduino (make sure the side with the SD card is close to the edge to make it ease to access) and solder the needed pins, then with jumper wires cut to size, create the connections across the parts based on the above pinouts.

Then place the OLED over the DFPlayer and solder all 4 pins onto the board then using jumper wire connect it to the needed pins.

Full Software - Tamagotchi

MP3 Player(2).jpg

Upload software

Then depending on the specific boards port (my nano has a usb-c port) connect it to a computer with the arduino IDE installed. And upload the attached file, or you can find the code on my GitHub: ISOPOD GitHub.

This code:

  1. Checks the button inputs for music and sound control
  2. displays the battery, volume level and track number
  3. Double click for game mode: isopod character dances if there is music, is idle during time out and sleeps after 5s with no music.

The ISOPOD graphics are stored as bitmaps within the file. If you want to use other graphics, websites like: https://javl.github.io/image2cpp/ can be used to covert images to bitmaps. (Remember to set the correct width and height within the code and when converting the image)

Full code:

#include <DFRobotDFPlayerMini.h>
#include <SoftwareSerial.h>
#include <U8g2lib.h>

// OLED Display
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

// DFPlayer
SoftwareSerial mySerial(10, 11);
DFRobotDFPlayerMini myDFPlayer;

// Buttons
#define buttonNext 3
#define buttonPause 4
#define buttonPrevious 5
#define ACTIVATED LOW

// State
int currentTrack = 1;
bool isPlaying = true;
int currentVolume = 20;
int currentPage = 0; // 0 = Home, 1 = Game

// Double-click handling
bool pauseClicked = false;
unsigned long lastPauseClickTime = 0;
const unsigned long doubleClickThreshold = 250; // milliseconds
bool waitingForSecondClick = false;

unsigned long lastAnimTime = 0;
uint8_t animFrame = 0;
const unsigned long animInterval = 250; // ms between frames

void setup()
{
u8g2.begin();

pinMode(buttonPause, INPUT_PULLUP);
pinMode(buttonNext, INPUT_PULLUP);
pinMode(buttonPrevious, INPUT_PULLUP);

mySerial.begin(9600);
delay(3000);

if (!myDFPlayer.begin(mySerial))
{
drawError("DFPlayer Error");
while (1)
;
}

myDFPlayer.volume(currentVolume);
myDFPlayer.play(currentTrack);

flashPage();
delay(2000);
updateDisplay();
}

void loop()
{
static bool updateNeeded = false;

// ---- Pause Button (Single click or Double-click) ----
if (digitalRead(buttonPause) == ACTIVATED)
{
unsigned long now = millis();

if (waitingForSecondClick && (now - lastPauseClickTime < doubleClickThreshold))
{
// Double-click: Change page
currentPage = (currentPage == 0) ? 1 : 0;
waitingForSecondClick = false;
pauseClicked = false;
updateNeeded = true;
while (digitalRead(buttonPause) == ACTIVATED)
;
delay(50); // debounce
}
else if (!pauseClicked)
{
pauseClicked = true;
lastPauseClickTime = now;
waitingForSecondClick = true;
while (digitalRead(buttonPause) == ACTIVATED)
;
delay(50); // debounce
}
}

// Handle single click after timeout
if (waitingForSecondClick && (millis() - lastPauseClickTime > doubleClickThreshold))
{
if (pauseClicked)
{
isPlaying = !isPlaying; // Toggle state
if (isPlaying)
{
myDFPlayer.start(); // Play (no need to check success)
}
else
{
myDFPlayer.pause(); // Pause
}
updateNeeded = true;
pauseClicked = false;
waitingForSecondClick = false;
}
}

// ---- Next Button ----
static unsigned long buttonNextPressedTime = 0;
if (digitalRead(buttonNext) == ACTIVATED)
{
if (buttonNextPressedTime == 0)
{
buttonNextPressedTime = millis();
}
else if (millis() - buttonNextPressedTime > 800)
{
if (currentVolume < 30)
currentVolume++;
myDFPlayer.volume(currentVolume); // Send it anyway
updateNeeded = true;
delay(300);
}
}
else if (buttonNextPressedTime != 0)
{
if (millis() - buttonNextPressedTime < 800)
{
currentTrack++;
myDFPlayer.play(currentTrack); // Send it anyway
isPlaying = true;
}
buttonNextPressedTime = 0;
updateNeeded = true;
}

// ---- Previous Button ----
static unsigned long buttonPreviousPressedTime = 0;
if (digitalRead(buttonPrevious) == ACTIVATED)
{
if (buttonPreviousPressedTime == 0)
{
buttonPreviousPressedTime = millis();
}
else if (millis() - buttonPreviousPressedTime > 800)
{
if (currentVolume > 0)
currentVolume--;
myDFPlayer.volume(currentVolume);
updateNeeded = true;
delay(300);
}
}
else if (buttonPreviousPressedTime != 0)
{
if (millis() - buttonPreviousPressedTime < 800)
{
if (currentTrack > 1)
currentTrack--;
myDFPlayer.play(currentTrack);
isPlaying = true;
}
buttonPreviousPressedTime = 0;
updateNeeded = true;
}

// ---- Update OLED Display ----

// ---- Animation timer for Game page ----
if (currentPage == 1 && millis() - lastAnimTime > animInterval)
{
animFrame = 1 - animFrame;
lastAnimTime = millis();
updateNeeded = true;
}

if (updateNeeded)
{
updateDisplay();
updateNeeded = false;
}
}

// ----------------- UI Functions -----------------

const uint8_t bitmap_dance_width = 40, bitmap_dance_height = 30;
const uint8_t bitmap_dance2_width = 42, bitmap_dance2_height = 28;
const uint8_t bitmap_eep_width = 38, bitmap_eep_height = 48;
const uint8_t bitmap_eep2_width = 38, bitmap_eep2_height = 48;

// Bitmap for Isopod
const unsigned char epd_bitmap_isopod[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00,
0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00,
0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00, 0x30, 0x00, 0x00, 0xfc, 0x0f, 0x30, 0x00, 0x00, 0xfc, 0x0f, 0x30, 0x00, 0x00, 0x03, 0x3c,
0x3c, 0x00, 0x00, 0x03, 0x3c, 0x3c, 0x00, 0x00, 0xcf, 0xf3, 0x0c, 0x00, 0x00, 0xcf, 0xf3, 0x0c,
0x00, 0xf0, 0xf3, 0xcf, 0xff, 0x00, 0xf0, 0xf3, 0xcf, 0xff, 0x00, 0xf3, 0xfc, 0xf3, 0x3f, 0x00,
0xf3, 0xfc, 0xf3, 0x3f, 0xf0, 0xfc, 0xfc, 0x0c, 0xcf, 0xf0, 0xfc, 0xfc, 0x0c, 0xcf, 0x3c, 0xff,
0xfc, 0xf0, 0x3c, 0x3c, 0xff, 0xfc, 0xf0, 0x3c, 0x3f, 0x0f, 0x33, 0x0f, 0x03, 0x3f, 0x0f, 0x33,
0x0f, 0x03, 0x00, 0x30, 0xcf, 0x33, 0x0f, 0x00, 0x30, 0xcf, 0x33, 0x0f};

// '1-idel', 40x28px
const unsigned char bitmap_idel[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00,
0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00,
0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00, 0x30, 0x00, 0x00, 0xfc, 0x0f, 0x30, 0x00, 0x00, 0xfc, 0x0f, 0x30, 0x00, 0x00, 0x03, 0x3c,
0x3c, 0x00, 0x00, 0x03, 0x3c, 0x3c, 0x00, 0x00, 0xcc, 0xf3, 0x0c, 0x00, 0x00, 0xcc, 0xf3, 0x0c,
0x00, 0xf0, 0xf3, 0xcf, 0x3f, 0x00, 0xf0, 0xf3, 0xcf, 0x3f, 0x00, 0xf3, 0xfc, 0xf3, 0x3f, 0x00,
0xf3, 0xfc, 0xf3, 0x3f, 0xf0, 0xfc, 0xfc, 0x0c, 0xff, 0xf0, 0xfc, 0xfc, 0x0c, 0xff, 0x3c, 0xff,
0xfc, 0xf0, 0x3c, 0x3c, 0xff, 0xfc, 0xf0, 0x3c, 0x3f, 0x0f, 0x33, 0x0f, 0x03, 0x3f, 0x0f, 0x33,
0x0f, 0x03, 0x00, 0x30, 0xcf, 0x33, 0x0f, 0x00, 0x30, 0xcf, 0x33, 0x0f};

// 'dance', 40x30px
const unsigned char bitmap_dance[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00,
0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xfc, 0x0f,
0x30, 0x00, 0x00, 0xfc, 0x0f, 0x30, 0x00, 0x00, 0x03, 0x3c, 0x0c, 0x00, 0x00, 0x03, 0x3c, 0x0c,
0x00, 0xf0, 0xf0, 0xf3, 0x0c, 0x00, 0xf0, 0xf0, 0xf3, 0x0c, 0x00, 0xfc, 0xfc, 0xcf, 0x3f, 0x00,
0xfc, 0xfc, 0xcf, 0x3f, 0x00, 0xf3, 0xfc, 0xf3, 0xff, 0x00, 0xf3, 0xfc, 0xf3, 0xff, 0xf0, 0xfc,
0xfc, 0x0c, 0xff, 0xf0, 0xfc, 0xfc, 0x0c, 0xff, 0x3f, 0xcf, 0xfc, 0xf0, 0x3c, 0x3f, 0xcf, 0xfc,
0xf0, 0x3c, 0x3f, 0x33, 0x33, 0x0f, 0x03, 0x3f, 0x33, 0x33, 0x0f, 0x03, 0x00, 0xfc, 0x0f, 0xcf,
0x0f, 0x00, 0xfc, 0x0f, 0xcf, 0x0f};

// '5-dance', 42x28px
const unsigned char bitmap_dance2[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xf0, 0x3f,
0xc0, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x0c, 0xf0, 0xc0, 0x00, 0x00, 0x00,
0x0c, 0xf0, 0xc0, 0x00, 0x00, 0x00, 0x33, 0xcf, 0x33, 0x00, 0x00, 0x00, 0x33, 0xcf, 0x33, 0x00,
0x00, 0xc0, 0xcf, 0x3f, 0xff, 0x00, 0x00, 0xc0, 0xcf, 0x3f, 0xff, 0x00, 0x00, 0xcc, 0xf3, 0xcf,
0xff, 0x00, 0x00, 0xcc, 0xf3, 0xcf, 0xff, 0x00, 0xff, 0xf3, 0xf3, 0x33, 0xfc, 0x03, 0xff, 0xf3,
0xf3, 0x33, 0xfc, 0x03, 0xfc, 0xfc, 0xf3, 0xc3, 0xf3, 0x00, 0xfc, 0xfc, 0xf3, 0xc3, 0xf3, 0x00,
0xf0, 0x3c, 0xcc, 0x3c, 0x0c, 0x00, 0xf0, 0x3c, 0xcc, 0x3c, 0x0c, 0x00, 0x00, 0xc0, 0x3c, 0xcf,
0xfc, 0x00, 0x00, 0xc0, 0x3c, 0xcf, 0xfc, 0x00};

// '2-eep', 38x48px
const unsigned char bitmap_eep[] PROGMEM = {
0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00,
0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0x00,
0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00,
0x0c, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x0c, 0x00, 0x00, 0xc0, 0xff,
0x0c, 0x00, 0x00, 0xc0, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30,
0x00, 0x00, 0xfc, 0x0f, 0x30, 0x00, 0x00, 0xfc, 0x0f, 0x30, 0x00, 0x00, 0x03, 0x3c, 0x3c, 0x00,
0x00, 0x03, 0x3c, 0x3c, 0x00, 0x00, 0xcc, 0xf3, 0x0c, 0x00, 0x00, 0xcc, 0xf3, 0x0c, 0x00, 0xf0,
0xf3, 0xcf, 0x3f, 0x00, 0xf0, 0xf3, 0xcf, 0x3f, 0x00, 0xf3, 0xfc, 0xf3, 0x3f, 0x00, 0xf3, 0xfc,
0xf3, 0x3f, 0xf0, 0xfc, 0xfc, 0xfc, 0x0f, 0xf0, 0xfc, 0xfc, 0xfc, 0x0f, 0x3c, 0xff, 0xfc, 0x00,
0x3c, 0x3c, 0xff, 0xfc, 0x00, 0x3c, 0x3f, 0x3f, 0xc3, 0x33, 0x03, 0x3f, 0x3f, 0xc3, 0x33, 0x03};
// '3-eep', 38x48px
const unsigned char bitmap_eep2[] PROGMEM = {
0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xc0,
0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0xf0, 0x3f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00,
0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0xc0, 0x0f, 0x00, 0x0c, 0x00, 0xc0, 0x0f,
0x00, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x0c, 0x00, 0xc0, 0x0f, 0x00,
0x30, 0x00, 0xc0, 0x0f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30,
0x00, 0x00, 0xfc, 0x0f, 0x30, 0x00, 0x00, 0xfc, 0x0f, 0x30, 0x00, 0x00, 0x03, 0x3c, 0x0c, 0x00,
0x00, 0x03, 0x3c, 0x0c, 0x00, 0x00, 0xcc, 0xf3, 0x0c, 0x00, 0x00, 0xcc, 0xf3, 0x0c, 0x00, 0xf0,
0xf3, 0xcf, 0x3f, 0x00, 0xf0, 0xf3, 0xcf, 0x3f, 0x00, 0xf3, 0xfc, 0xf3, 0x3f, 0x00, 0xf3, 0xfc,
0xf3, 0x3f, 0xf0, 0xfc, 0xfc, 0xfc, 0x0f, 0xf0, 0xfc, 0xfc, 0xfc, 0x0f, 0x3c, 0xff, 0xfc, 0x00,
0x3c, 0x3c, 0xff, 0xfc, 0x00, 0x3c, 0x3f, 0x3f, 0xc3, 0x33, 0x03, 0x3f, 0x3f, 0xc3, 0x33, 0x03};

// start page
void flashPage()
{
u8g2.clearBuffer();
u8g2.drawFrame(10, 10, 108, 44);
u8g2.setFont(u8g2_font_pcsenior_8u);
u8g2.drawXBMP(60, 25, 40, 28, epd_bitmap_isopod);
u8g2.setCursor(30, 35);
u8g2.print(F("ISOPOD"));
u8g2.sendBuffer();
}

// header
void drawHeader()
{
u8g2.setDrawColor(1);
u8g2.drawFrame(0, 0, 128, 14);

u8g2.setFont(u8g2_font_open_iconic_embedded_1x_t);
if (currentPage == 0)
{
u8g2.drawGlyph(5, 11, 0x0040); // Home icon
}
else
{
u8g2.setFont(u8g2_font_unifont_t_animals);
u8g2.drawGlyph(5, 11, 0x0230); // Animal icon
}

u8g2.setFont(u8g2_font_5x8_tf);
u8g2.setCursor(90, 11);
u8g2.print("VOL ");
u8g2.print(currentVolume);

u8g2.setDrawColor(1);
}

// draw the page to screen
void updateDisplay()
{
u8g2.clearBuffer();
drawHeader();

if (currentPage == 0)
{
drawHomePage();
}
else
{
drawGamePage();
}

u8g2.sendBuffer();
}

// home page
void drawHomePage()
{
u8g2.drawFrame(0, 15, 128, 33);

u8g2.setFont(u8g2_font_pcsenior_8u);
u8g2.setCursor(10, 35);
u8g2.print("SONG:");
u8g2.setCursor(60, 35);
u8g2.print(currentTrack);

u8g2.drawFrame(0, 50, 128, 14);

u8g2.setFont(u8g2_font_open_iconic_play_1x_t);
u8g2.drawGlyph(25, 61, 0x0047); // Previous
u8g2.drawGlyph(60, 61, isPlaying ? 0x0044 : 0x0045); // Play/Pause
u8g2.drawGlyph(95, 61, 0x0048); // Next
}

// isopod page
void drawGamePage()
{
u8g2.drawFrame(0, 15, 128, 49);

// Bottom-right corner for all images
const int x_br = 75, y_br = 63;

if (isPlaying)
{
if (animFrame == 0)
{
u8g2.drawXBMP(
x_br - bitmap_dance_width,
y_br - bitmap_dance_height,
bitmap_dance_width,
bitmap_dance_height,
bitmap_dance);
}
else
{
u8g2.drawXBMP(
x_br - bitmap_dance2_width,
y_br - bitmap_dance2_height,
bitmap_dance2_width,
bitmap_dance2_height,
bitmap_dance2);
}
}
else
{
if (animFrame == 0)
{
u8g2.drawXBMP(
x_br - bitmap_eep_width,
y_br - bitmap_eep_height,
bitmap_eep_width,
bitmap_eep_height,
bitmap_eep);
}
else
{
u8g2.drawXBMP(
x_br - bitmap_eep2_width,
y_br - bitmap_eep2_height,
bitmap_eep2_width,
bitmap_eep2_height,
bitmap_eep2);
}
}
}

void drawError(const char *msg)
{
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.drawStr(0, 30, msg);
u8g2.sendBuffer();
}

Utility Belt

MP3 Player (1).jpg
MP3 Player(3).jpg
MP3 Player(4).jpg

Direct Circuit to belt

With the metal clips and string, attach the connectors to the holes on the edge of the PCB.

  1. This will be one connection method to a belt, however, this is less secure and safe for the device as the components are exposed.
  2. So, along with this, I will also create a casing with cardboard and duck tape, then a dedicated utility belt with a space for the mp3 player.

ISOPOD Container

TinkerCad 3D design Files: Container File and Prototype File

In the future I could also 3D print a stronger case from the above container files.

Based on the designs I have reused a shoe box's cardboard to create a simple container with duck tape.

Utility Belt

For a way to store the container on a belt I am using scrap fabric to create a utility belt specifically for the ISOPODs container. The stages for making it is shown in the images.

Connecting the Output Device

MP3 Player (2).jpg
MP3 Player(5).jpg

Upcycled Headphones

After taking apart my broken Bluetooth headphones (Bluetooth modal no longer works) I was able to see the SPK1 and SPK2 connector where I will be rewiring it to the mp3 player so i can make use of the functional speakers and structure.

  1. Drill a small hole in the headphone casing to allow the wire to go through clean.
  2. Solder two wires to the SPK 1 and 2 connectors on the headphones Making sure to run them through the whole.
  3. Then connect the ends to an audio jack.
  4. Make sure the two outputs for the mp3 player have been connected to an audio port - which will allow me to connect any output device.
  5. Or you could directly wire the headphones to the MP3 Player but it will make it hard to replace.

*Side note

I have found a broken intercom system and will also be temporally rewiring the output to the mp3 player because it looks quite funny and can fit well in the utility belt, (not a permanent solution but why not)

mp3 player inspired by: @Neutrino1

All images, diagrams and code attached has been created by me.

I created all circuit diagrams with cirkitdesigner, my project link.