mirror of
https://github.com/Threnklyn/esphome-dev.git
synced 2026-05-22 13:48:29 +02:00
2f07225984
* Move stop/is_running implementation to Action base class Try to fix issue #1105. Until now if an UpdateComponentAction, a LambdaAction, or any action that can contain those inside their "else" or "then" action lists, resulted in a call to script.stop on the script that contains them, the script would continue running, because they didn't implement a stop() method. Basically only the asynchronous ones did: DelayAction, WaitUntilAction and ScriptWaitAction. With this change num_running_ in Action replaces DelayAction::num_running_ and WaitUntilAction::triggered_ to provide the same is_running logic to other actions. * Make some Action methods protected Apparently play()/stop() etc. are not meant to be called directly by users of the class and if they're called directly that would not give the expected result for the classes that have an empty play(). Make all methods except play_complex, stop_comples and is_running protected. While there also make RemoteTransmitterActionBase::encode protected. * lint * format Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>
198 lines
5.2 KiB
C++
198 lines
5.2 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_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 : 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 PlayFileAction : public Action<Ts...>, public Parented<DFPlayer> {
|
|
public:
|
|
TEMPLATABLE_VALUE(uint16_t, file)
|
|
TEMPLATABLE_VALUE(boolean, 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(boolean, 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)
|
|
|
|
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
|