Tim's blah blah blah

🎼 Hearmony: DIY Children's Music Player built on ESP8266

(Updated: )

Contents

Inspired by Hörbert and Toniebox we decided to make our own: Hearmony. We build on Ronau’s Hörbert clone and Westlicht’s Pleya, and customize where we see fit.

Other related projects are TinyDFPlayer, DIY Music Player Using ATtiny85, and Attiny85 SD Player

We’re currently drafting requirements and making a plan.

Requirements

We have an audience of children of 1-4 years old in mind.

  1. Music
    1. Plays 9 different songs from removable memory card
    2. Music quality slightly better than ‘button books’ (>=32kbit mp3 mono)
    3. Volume pre-set, configurable via software
    4. Current song stops (can be interrupted) if new song is started
    5. Stop button (can be same as off button)
  2. Battery
    1. Battery should last 1 (target: 3) months @ 30min/day = 15 (target: 45) hours.
    2. Device should power-off automatically if forgotten
    3. Batteries should be replaceable, ideally 4xAA
  3. Casing
    1. Non-toxic (finish)
    2. Sturdy, drop-safe from 50cm height
    3. Can be carried around by Weight <1kg (?)
    4. Sturdy buttons that don’t break easily
    5. Should open easily to replace batteries
    6. Have opening for micro-USB charging

Bill of Materials

This is the current BoM (under development):

  1. Casing (xx)
  2. Electronics (~22€)
    1. MCU/SoC: Pro Mini clone - 5€
    2. Speaker: 75mm speaker - 8 ohm 1 Watt 3€
    3. Buttons: Tactile pushbutton 12mmx12mm + button caps - 4€/10
    4. On/off button & circuit: pushbutton 122mm + Pololu latch circuit - 4€
    5. Battery holders: 4xAA battery holder - 1.5€
    6. Amplifier: PAM8403 2x3W amp - 1.5€
    7. Memory: SD card adapter module - 2.5€
  3. Batteries (14€): 4xAA Eneloop Pro 2500mAh - 14€
  4. Software (0€): Native Arduino IDE + TMRpcm via wokwi

Electronics

Battery time is putting most constraints on the electronics design, so we start with that. To get 15 hours play time with 4 AAA @ 2500 mAh, I can use 166 mA @ 5V maximum. My power budget looks as follows:

Additionally, I need an automatic power-off circuit to minimize idle power consumption to near-zero.

Given this budget, I investigated what options exist.

Hardware options

There are a range of chips on the market to play music.

Having said that, I grouped the above into four options with concrete parts:

  1. Option 1 (mp3, easy, high power use): WeMos D1 mini/ESP8266 (5€) + dfplayer (5€) + SD card (3€) + latch circuit (4€) = 17€
  2. Option 2 (mp3, super easy, no auto power-off, expensive): Adafruit Audio FX/VLSI (30€) = 30€
  3. Option 3 (mp3, medium, needs re-soldering dfplayer): Arduino Pro Mini 3.3V/ATmega328P (5€) + YX5200 (5€) + PAM8302 (2€) + SD card (3€) + latch circuit (4€) = 19€
  4. Option 4 (wav, medium, use software to play pcm wav): Arduino Pro Mini 3.3V/ATmega328P (5€) + PAM8302 (2€) + SD card (3€) + latch circuit (4€) = 14€
  5. Option 5 (mp3, medium, use software mp3 decoding, high power use?): Teensy3.2/Cortex M4 20$ + PAM8302 (2€) + SD card (3€) + latch circuit (4€) = 25€

More details on above parts:

part consumption (mA) charging/power logic decoding amplification
Adafruit Audio FX Sound Board 16MB 30mA X X X X
Wemos D1 mini 27mA** X X
ESP8266EX 15mA** X
ATMega32u4 <5mA* X
Arduino Nano 19mA X X
Teensy 3.2 ?mA X X
Sparkfun Pro Mini 3.3V ~10mA X
ATmega328P 1.5mA X
VS1053b 10-37mA? X
YX5200 15mA X
KT403A 15mA X
BY8301 16mA? X X X
8002A 100mA X
PAM8403 15mA X
PAM8302 <15mA? X
Pushbutton Power Switch <1µA (off) X

* at 4MHz ** at modem sleep (i.e. no wifi)

Logic/interface requirements

For the logic & interface, it needs to:

  1. Take user input (buttons)
  2. Control the auto-power down (latching circuit)
  3. Store music in some memory
  4. Read & decode music and drive an amplifier

For the audio part and interface part, I need buttons (5€, oem) + speaker 1W 8Ω (3€, adafruit) + batteries (eneloop, 15€) = 23€ in total.

Battery options

We use AA NiMH for ease of finding good quality, no down-time when recharging, in spite of what DIYI0T says. Also, the discharge curve of NiMH batteries is quite favorable as the voltge is within the input range for a long time.

Software

https://wokwi.com/arduino/projects/316627468467307072

Buttons - native/Keypad.h

Using Chris–A’s Keypad library we can make a matrix keypad which uses fewer GPIOs. It’s very simple to use:

#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
	{'1','2','3'},
	{'4','5','6'},
	{'7','8','9'},
	{'*','0','#'}
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup(){
	Serial.begin(9600);
}
	
void loop(){
	char key = keypad.getKey();
	
	if (key){
		Serial.println(key);
	}
}

Buttons - esphome.io

For ESP, we would use esphome.io and use GPIOs on the ESP to make buttons. Unfortunately it doesn’t have a matrix keypad library (update: maybe it does), so we hack something together. We use one button as ‘shift’ key to double the combinations (for n GPIOs we can make 2^n combinations, but we only need 9). Below how we would implement this for D2.

# Make buttons D1 (meta key), D2, D3, D5, D6, D7
binary_sensor:
	- platform: gpio
		name: "Button1"
		id: buttonid1
		pin:
			number: D1
			inverted: true
			mode:
				input: true
				pullup: true
		filters:
			- delayed_off: 100ms

	- platform: gpio
		name: "Button2"
		pin:
			number: D2
			inverted: true
			mode:
				input: true
				pullup: true
		on_press:
			then:
			- delay: 100ms
			- if:
					condition: 
						- binary_sensor.is_on: buttonid1
					then:
						- logger.log: "Button1 is on"
						- light.turn_on: statusled
					else:
						- logger.log: "Button1 is off"
						- light.turn_off: statusled

WAV playing - TMRpcm

TMRh20’s TMRpcm library plays 8bit 30kHz WAV files natively on an Arduino.

MP3 playing - esphome.io

  1. Get music 1. Get from Youtube using youtube-dl: youtube-dl --extract-audio --audio-format mp3 cU-_st6Ksac
  2. Copy your mp3 into you micro SD card 1. NOTE: The order you copy the mp3 into micro SD card will affect the order mp3 played , which means play(1) function will play the first mp3 copied into micro SD card. 2. For Mac users: run dot_clean /Volumes/<SDVolumeName> to prevent hidden files.
  3. Configure dfplayer for esphome.io
# Use UART2 on ESP8266 (https://esphome.io/components/uart.html & https://randomnerdtutorials.com/esp8266-pinout-reference-gpios/)
uart:
	id: uart2 
	tx_pin: GPIO2 # D4 (HIGH at boot; connected to on-board LED, boot fails if pulled LOW)
	rx_pin: GPIO0 # D3 (connected to FLASH button, boot fails if pulled LOW)
	baud_rate: 9600

# Declare DFPlayer mini module
dfplayer:
	uart_id: uart2
  1. Bind play event to some action, first stop in case it’s running, then play new song
	on_press:
		then:
			- dfplayer.stop
			- dfplayer.play:
					file: 1
					loop: false

Casing

TODO plan casing approach. Use existing briefcase? e.g. Houten Koffertje ca.18x13x5,5cm

#arduino #diy