Update: use I²S Audio Media Player — ESPHome instead
original post:
I don’t know if someone else is interested in playing sounds with ESPHome
TLTR: https://www.youtube.com/watch?v=RI8nUdsZprM
The hardware I’m using is an ESP8266 / D1 mini, a BC338 and a 470ohm resistant. The xtensia arduino plugin is 2.5.2 and ESP8266Audio 1.1.3 with my patch - Allow playing wav files via HTTPStream by ferbar · Pull Request #224 · earlephilhower/ESP8266Audio · GitHub. In addition to my patch I had to comment-out AudioFileSourceSD in the .h and .cpp file.
Until now I didn’t manage to play a mp3 - not enough free ram …
My hint: disconnect the speaker while flashing the esp
esphome:
name: $devicename
platform: ESP8266
board: nodemcuv2
arduino_version: 2.5.2
libraries:
- esp8266Audio
includes:
- EsphomeAudio.h
switch:
- platform: custom
lambda: |-
auto esphomeAudio = new EsphomeAudio();
App.register_component(esphomeAudio);
return {esphomeAudio};
switches:
name: "Play Sound"
EsphomeAudio.h:
#include "esphome.h"
#include <alloca.h>
#include <AudioFileSourceSPIFFS.h>
#include "AudioFileSourceHTTPStream.h"
#include "AudioGeneratorWAV.h"
#include "AudioOutputI2SNoDAC.h"
#include "AudioFileSourceBuffer.h"
#include "AudioGenerator.h"
static const char *TAG = "audio";
#define DEBUGf(format, ...) Serial.printf(format "\n", ##__VA_ARGS__)
/**
* im cbData muss das TAG stehn - vom regster
*/
void statusCBFn(void *cbData, int code, const char *message) {
// PROGMEM vs RAM
if (message >= (const char *)0x40000000) {
char *s=(char *) alloca(strlen_P(message));
strcpy_P(s, message);
message=s;
}
DEBUGf("'%s': code:%d statusCBFn: %s", (char *) cbData, code, message);
}
// == RX
#define I2SO_DATA 3
class EsphomeAudio : public Component, public Switch {
public:
EsphomeAudio() : wav(NULL), file(NULL), out(NULL), buff(NULL) {}
void setup() override {
pinMode(I2SO_DATA, OUTPUT);
digitalWrite(I2SO_DATA,false);
}
void loop() override {
if (this->wav && this->wav->isRunning()) {
if (!this->wav->loop()) {
this->wav->stop();
delete(this->wav); this->wav=NULL;
delete(this->buff); this->buff=NULL;
delete(this->out); this->out=NULL;
delete(this->file); this->file=NULL;
pinMode(I2SO_DATA, OUTPUT);
digitalWrite(I2SO_DATA,false);
this->publish_state(false);
}
}
}
void write_state(bool state) override {
if(state && !this->file) {
DEBUGf("%s: init i2s %s", this->get_name().c_str(), state ? "ON" : "OFF");
this->file = new AudioFileSourceHTTPStream("http://home-assistant/old-car-engine_daniel_simion.wav");
this->file->RegisterStatusCB(statusCBFn, (void *) "AudioFileSourceHTTPStream");
// Create a buffer using that stream
this->buff = new AudioFileSourceBuffer(this->file, 2048);
this->buff->RegisterStatusCB(statusCBFn, (void *) "AudioFileSourceBuffer");
this->out = new AudioOutputI2SNoDAC();
this->out->RegisterStatusCB(statusCBFn, (void *) "AudioOutputI2SNoDAC");
this->wav = new AudioGeneratorWAV();
this->wav->RegisterStatusCB(statusCBFn, (void *) "AudioGeneratorWAV");
uint32_t free = ESP.getFreeHeap();
DEBUGf("%s:wav->begin, free=%d", this->get_name().c_str(), free);
if(this->wav->begin(this->buff, this->out)) {
DEBUGf("%s: started playing", this->get_name().c_str());
} else {
DEBUGf("%s: failed to play", this->get_name().c_str());
}
this->publish_state(state);
}
}
~EsphomeAudio() {
DEBUGf("%s:~EsphomeAudio", this->get_name().c_str());
if(this->file)
this->file->RegisterStatusCB(NULL, NULL);
}
private:
AudioGeneratorWAV *wav;
AudioFileSourceHTTPStream *file;
AudioOutputI2SNoDAC *out;
AudioFileSourceBuffer *buff;
};