mirror of
https://github.com/esphome/esphome.git
synced 2024-12-02 11:44:13 +01:00
216 lines
5.7 KiB
C++
216 lines
5.7 KiB
C++
#pragma once
|
|
|
|
#include "esphome/core/component.h"
|
|
#include "esphome/components/uart/uart.h"
|
|
#include "esphome/core/automation.h"
|
|
|
|
const size_t DFPLAYER_READ_BUFFER_LENGTH = 25; // two messages + some extra
|
|
|
|
namespace esphome {
|
|
namespace dfplayer {
|
|
|
|
enum EqPreset {
|
|
NORMAL = 0,
|
|
POP = 1,
|
|
ROCK = 2,
|
|
JAZZ = 3,
|
|
CLASSIC = 4,
|
|
BASS = 5,
|
|
};
|
|
|
|
enum Device {
|
|
USB = 1,
|
|
TF_CARD = 2,
|
|
};
|
|
|
|
class DFPlayer : public uart::UARTDevice, public Component {
|
|
public:
|
|
void loop() override;
|
|
|
|
void next() {
|
|
this->ack_set_is_playing_ = true;
|
|
this->send_cmd_(0x01);
|
|
}
|
|
void previous() {
|
|
this->ack_set_is_playing_ = true;
|
|
this->send_cmd_(0x02);
|
|
}
|
|
void play_mp3(uint16_t file) {
|
|
this->ack_set_is_playing_ = true;
|
|
this->send_cmd_(0x12, file);
|
|
}
|
|
void play_file(uint16_t file) {
|
|
this->ack_set_is_playing_ = true;
|
|
this->send_cmd_(0x03, file);
|
|
}
|
|
void play_file_loop(uint16_t file) {
|
|
this->ack_set_is_playing_ = true;
|
|
this->send_cmd_(0x08, file);
|
|
}
|
|
void play_folder(uint16_t folder, uint16_t file);
|
|
void play_folder_loop(uint16_t folder) {
|
|
this->ack_set_is_playing_ = true;
|
|
this->send_cmd_(0x17, folder);
|
|
}
|
|
void volume_up() { this->send_cmd_(0x04); }
|
|
void volume_down() { this->send_cmd_(0x05); }
|
|
void set_device(Device device) { this->send_cmd_(0x09, device); }
|
|
void set_volume(uint8_t volume) { this->send_cmd_(0x06, volume); }
|
|
void set_eq(EqPreset preset) { this->send_cmd_(0x07, preset); }
|
|
void sleep() {
|
|
this->ack_reset_is_playing_ = true;
|
|
this->send_cmd_(0x0A);
|
|
}
|
|
void reset() {
|
|
this->ack_reset_is_playing_ = true;
|
|
this->send_cmd_(0x0C);
|
|
}
|
|
void start() {
|
|
this->ack_set_is_playing_ = true;
|
|
this->send_cmd_(0x0D);
|
|
}
|
|
void pause() {
|
|
this->ack_reset_is_playing_ = true;
|
|
this->send_cmd_(0x0E);
|
|
}
|
|
void stop() {
|
|
this->ack_reset_is_playing_ = true;
|
|
this->send_cmd_(0x16);
|
|
}
|
|
void random() {
|
|
this->ack_set_is_playing_ = true;
|
|
this->send_cmd_(0x18);
|
|
}
|
|
|
|
bool is_playing() { return is_playing_; }
|
|
void dump_config() override;
|
|
|
|
void add_on_finished_playback_callback(std::function<void()> callback) {
|
|
this->on_finished_playback_callback_.add(std::move(callback));
|
|
}
|
|
|
|
protected:
|
|
void send_cmd_(uint8_t cmd, uint16_t argument = 0);
|
|
void send_cmd_(uint8_t cmd, uint16_t high, uint16_t low) {
|
|
this->send_cmd_(cmd, ((high & 0xFF) << 8) | (low & 0xFF));
|
|
}
|
|
uint8_t sent_cmd_{0};
|
|
|
|
char read_buffer_[DFPLAYER_READ_BUFFER_LENGTH];
|
|
size_t read_pos_{0};
|
|
|
|
bool is_playing_{false};
|
|
bool ack_set_is_playing_{false};
|
|
bool ack_reset_is_playing_{false};
|
|
|
|
CallbackManager<void()> on_finished_playback_callback_;
|
|
};
|
|
|
|
#define DFPLAYER_SIMPLE_ACTION(ACTION_CLASS, ACTION_METHOD) \
|
|
template<typename... Ts> \
|
|
class ACTION_CLASS : /* NOLINT */ \
|
|
public Action<Ts...>, \
|
|
public Parented<DFPlayer> { \
|
|
void play(Ts... x) override { this->parent_->ACTION_METHOD(); } \
|
|
};
|
|
|
|
DFPLAYER_SIMPLE_ACTION(NextAction, next)
|
|
DFPLAYER_SIMPLE_ACTION(PreviousAction, previous)
|
|
|
|
template<typename... Ts> class PlayMp3Action : public Action<Ts...>, public Parented<DFPlayer> {
|
|
public:
|
|
TEMPLATABLE_VALUE(uint16_t, file)
|
|
|
|
void play(Ts... x) override {
|
|
auto file = this->file_.value(x...);
|
|
this->parent_->play_mp3(file);
|
|
}
|
|
};
|
|
|
|
template<typename... Ts> class PlayFileAction : public Action<Ts...>, public Parented<DFPlayer> {
|
|
public:
|
|
TEMPLATABLE_VALUE(uint16_t, file)
|
|
TEMPLATABLE_VALUE(bool, loop)
|
|
|
|
void play(Ts... x) override {
|
|
auto file = this->file_.value(x...);
|
|
auto loop = this->loop_.value(x...);
|
|
if (loop) {
|
|
this->parent_->play_file_loop(file);
|
|
} else {
|
|
this->parent_->play_file(file);
|
|
}
|
|
}
|
|
};
|
|
|
|
template<typename... Ts> class PlayFolderAction : public Action<Ts...>, public Parented<DFPlayer> {
|
|
public:
|
|
TEMPLATABLE_VALUE(uint16_t, folder)
|
|
TEMPLATABLE_VALUE(uint16_t, file)
|
|
TEMPLATABLE_VALUE(bool, loop)
|
|
|
|
void play(Ts... x) override {
|
|
auto folder = this->folder_.value(x...);
|
|
auto file = this->file_.value(x...);
|
|
auto loop = this->loop_.value(x...);
|
|
if (loop) {
|
|
this->parent_->play_folder_loop(folder);
|
|
} else {
|
|
this->parent_->play_folder(folder, file);
|
|
}
|
|
}
|
|
};
|
|
|
|
template<typename... Ts> class SetDeviceAction : public Action<Ts...>, public Parented<DFPlayer> {
|
|
public:
|
|
TEMPLATABLE_VALUE(Device, device)
|
|
|
|
void play(Ts... x) override {
|
|
auto device = this->device_.value(x...);
|
|
this->parent_->set_device(device);
|
|
}
|
|
};
|
|
|
|
template<typename... Ts> class SetVolumeAction : public Action<Ts...>, public Parented<DFPlayer> {
|
|
public:
|
|
TEMPLATABLE_VALUE(uint8_t, volume)
|
|
|
|
void play(Ts... x) override {
|
|
auto volume = this->volume_.value(x...);
|
|
this->parent_->set_volume(volume);
|
|
}
|
|
};
|
|
|
|
template<typename... Ts> class SetEqAction : public Action<Ts...>, public Parented<DFPlayer> {
|
|
public:
|
|
TEMPLATABLE_VALUE(EqPreset, eq)
|
|
|
|
void play(Ts... x) override {
|
|
auto eq = this->eq_.value(x...);
|
|
this->parent_->set_eq(eq);
|
|
}
|
|
};
|
|
|
|
DFPLAYER_SIMPLE_ACTION(SleepAction, sleep)
|
|
DFPLAYER_SIMPLE_ACTION(ResetAction, reset)
|
|
DFPLAYER_SIMPLE_ACTION(StartAction, start)
|
|
DFPLAYER_SIMPLE_ACTION(PauseAction, pause)
|
|
DFPLAYER_SIMPLE_ACTION(StopAction, stop)
|
|
DFPLAYER_SIMPLE_ACTION(RandomAction, random)
|
|
DFPLAYER_SIMPLE_ACTION(VolumeUpAction, volume_up)
|
|
DFPLAYER_SIMPLE_ACTION(VolumeDownAction, volume_down)
|
|
|
|
template<typename... Ts> class DFPlayerIsPlayingCondition : public Condition<Ts...>, public Parented<DFPlayer> {
|
|
public:
|
|
bool check(Ts... x) override { return this->parent_->is_playing(); }
|
|
};
|
|
|
|
class DFPlayerFinishedPlaybackTrigger : public Trigger<> {
|
|
public:
|
|
explicit DFPlayerFinishedPlaybackTrigger(DFPlayer *parent) {
|
|
parent->add_on_finished_playback_callback([this]() { this->trigger(); });
|
|
}
|
|
};
|
|
|
|
} // namespace dfplayer
|
|
} // namespace esphome
|