mirror of
https://github.com/esphome/esphome.git
synced 2024-12-23 22:14:54 +01:00
Add dfplayer mini component (#655)
* Add dfplayer mini component * receiving some data * implemented many actions * lint * undo homeassistant_time.h * Update esphome/components/dfplayer/__init__.py Co-Authored-By: Otto Winter <otto@otto-winter.com> * Update esphome/components/dfplayer/dfplayer.cpp Co-Authored-By: Otto Winter <otto@otto-winter.com> * add set device. fixes * lint * Fixes and sync with docs * add test * lint * lint * lint
This commit is contained in:
parent
89c1274d56
commit
54fe1c7d55
4 changed files with 593 additions and 0 deletions
221
esphome/components/dfplayer/__init__.py
Normal file
221
esphome/components/dfplayer/__init__.py
Normal file
|
@ -0,0 +1,221 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import automation
|
||||
from esphome.const import CONF_ID, CONF_TRIGGER_ID
|
||||
from esphome.components import uart
|
||||
|
||||
DEPENDENCIES = ['uart']
|
||||
|
||||
dfplayer_ns = cg.esphome_ns.namespace('dfplayer')
|
||||
DFPlayer = dfplayer_ns.class_('DFPlayer', cg.Component)
|
||||
DFPlayerFinishedPlaybackTrigger = dfplayer_ns.class_('DFPlayerFinishedPlaybackTrigger',
|
||||
automation.Trigger.template())
|
||||
DFPlayerIsPlayingCondition = dfplayer_ns.class_('DFPlayerIsPlayingCondition', automation.Condition)
|
||||
|
||||
MULTI_CONF = True
|
||||
CONF_FOLDER = 'folder'
|
||||
CONF_FILE = 'file'
|
||||
CONF_LOOP = 'loop'
|
||||
CONF_VOLUME = 'volume'
|
||||
CONF_DEVICE = 'device'
|
||||
CONF_EQ_PRESET = 'eq_preset'
|
||||
CONF_ON_FINISHED_PLAYBACK = 'on_finished_playback'
|
||||
|
||||
EqPreset = dfplayer_ns.enum("EqPreset")
|
||||
EQ_PRESET = {
|
||||
'NORMAL': EqPreset.NORMAL,
|
||||
'POP': EqPreset.POP,
|
||||
'ROCK': EqPreset.ROCK,
|
||||
'JAZZ': EqPreset.JAZZ,
|
||||
'CLASSIC': EqPreset.CLASSIC,
|
||||
'BASS': EqPreset.BASS,
|
||||
}
|
||||
Device = dfplayer_ns.enum("Device")
|
||||
DEVICE = {
|
||||
'USB': Device.USB,
|
||||
'TF_CARD': Device.TF_CARD,
|
||||
}
|
||||
|
||||
NextAction = dfplayer_ns.class_('NextAction', automation.Action)
|
||||
PreviousAction = dfplayer_ns.class_('PreviousAction', automation.Action)
|
||||
PlayFileAction = dfplayer_ns.class_('PlayFileAction', automation.Action)
|
||||
PlayFolderAction = dfplayer_ns.class_('PlayFolderAction', automation.Action)
|
||||
SetVolumeAction = dfplayer_ns.class_('SetVolumeAction', automation.Action)
|
||||
SetEqAction = dfplayer_ns.class_('SetEqAction', automation.Action)
|
||||
SleepAction = dfplayer_ns.class_('SleepAction', automation.Action)
|
||||
ResetAction = dfplayer_ns.class_('ResetAction', automation.Action)
|
||||
StartAction = dfplayer_ns.class_('StartAction', automation.Action)
|
||||
PauseAction = dfplayer_ns.class_('PauseAction', automation.Action)
|
||||
StopAction = dfplayer_ns.class_('StopAction', automation.Action)
|
||||
RandomAction = dfplayer_ns.class_('RandomAction', automation.Action)
|
||||
SetDeviceAction = dfplayer_ns.class_('SetDeviceAction', automation.Action)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(cv.Schema({
|
||||
cv.GenerateID(): cv.declare_id(DFPlayer),
|
||||
cv.Optional(CONF_ON_FINISHED_PLAYBACK): automation.validate_automation({
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DFPlayerFinishedPlaybackTrigger),
|
||||
}),
|
||||
}).extend(uart.UART_DEVICE_SCHEMA))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield uart.register_uart_device(var, config)
|
||||
|
||||
for conf in config.get(CONF_ON_FINISHED_PLAYBACK, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
yield automation.build_automation(trigger, [], conf)
|
||||
|
||||
|
||||
@automation.register_action('dfplayer.play_next', NextAction, cv.Schema({
|
||||
cv.GenerateID(): cv.use_id(DFPlayer),
|
||||
}))
|
||||
def dfplayer_next_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action('dfplayer.play_previous', PreviousAction, cv.Schema({
|
||||
cv.GenerateID(): cv.use_id(DFPlayer),
|
||||
}))
|
||||
def dfplayer_previous_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action('dfplayer.play', PlayFileAction, cv.maybe_simple_value({
|
||||
cv.GenerateID(): cv.use_id(DFPlayer),
|
||||
cv.Required(CONF_FILE): cv.templatable(cv.int_),
|
||||
cv.Optional(CONF_LOOP): cv.templatable(cv.boolean),
|
||||
}, key=CONF_FILE))
|
||||
def dfplayer_play_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
template_ = yield cg.templatable(config[CONF_FILE], args, float)
|
||||
cg.add(var.set_file(template_))
|
||||
if CONF_LOOP in config:
|
||||
template_ = yield cg.templatable(config[CONF_LOOP], args, float)
|
||||
cg.add(var.set_loop(template_))
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action('dfplayer.play_folder', PlayFolderAction, cv.Schema({
|
||||
cv.GenerateID(): cv.use_id(DFPlayer),
|
||||
cv.Required(CONF_FOLDER): cv.templatable(cv.int_),
|
||||
cv.Optional(CONF_FILE): cv.templatable(cv.int_),
|
||||
cv.Optional(CONF_LOOP): cv.templatable(cv.boolean),
|
||||
}))
|
||||
def dfplayer_play_folder_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
template_ = yield cg.templatable(config[CONF_FOLDER], args, float)
|
||||
cg.add(var.set_folder(template_))
|
||||
if CONF_FILE in config:
|
||||
template_ = yield cg.templatable(config[CONF_FILE], args, float)
|
||||
cg.add(var.set_file(template_))
|
||||
if CONF_LOOP in config:
|
||||
template_ = yield cg.templatable(config[CONF_LOOP], args, float)
|
||||
cg.add(var.set_loop(template_))
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action('dfplayer.set_device', SetDeviceAction, cv.maybe_simple_value({
|
||||
cv.GenerateID(): cv.use_id(DFPlayer),
|
||||
cv.Required(CONF_DEVICE): cv.enum(DEVICE, upper=True),
|
||||
}, key=CONF_DEVICE))
|
||||
def dfplayer_set_device_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
template_ = yield cg.templatable(config[CONF_DEVICE], args, Device)
|
||||
cg.add(var.set_device(template_))
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action('dfplayer.set_volume', SetVolumeAction, cv.maybe_simple_value({
|
||||
cv.GenerateID(): cv.use_id(DFPlayer),
|
||||
cv.Required(CONF_VOLUME): cv.templatable(cv.int_),
|
||||
}, key=CONF_VOLUME))
|
||||
def dfplayer_set_volume_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
template_ = yield cg.templatable(config[CONF_VOLUME], args, float)
|
||||
cg.add(var.set_volume(template_))
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action('dfplayer.set_eq', SetEqAction, cv.maybe_simple_value({
|
||||
cv.GenerateID(): cv.use_id(DFPlayer),
|
||||
cv.Required(CONF_EQ_PRESET): cv.templatable(cv.enum(EQ_PRESET, upper=True)),
|
||||
}, key=CONF_EQ_PRESET))
|
||||
def dfplayer_set_eq_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
template_ = yield cg.templatable(config[CONF_EQ_PRESET], args, EqPreset)
|
||||
cg.add(var.set_eq(template_))
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action('dfplayer.sleep', SleepAction, cv.Schema({
|
||||
cv.GenerateID(): cv.use_id(DFPlayer),
|
||||
}))
|
||||
def dfplayer_sleep_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action('dfplayer.reset', ResetAction, cv.Schema({
|
||||
cv.GenerateID(): cv.use_id(DFPlayer),
|
||||
}))
|
||||
def dfplayer_reset_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action('dfplayer.start', StartAction, cv.Schema({
|
||||
cv.GenerateID(): cv.use_id(DFPlayer),
|
||||
}))
|
||||
def dfplayer_start_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action('dfplayer.pause', PauseAction, cv.Schema({
|
||||
cv.GenerateID(): cv.use_id(DFPlayer),
|
||||
}))
|
||||
def dfplayer_pause_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action('dfplayer.stop', StopAction, cv.Schema({
|
||||
cv.GenerateID(): cv.use_id(DFPlayer),
|
||||
}))
|
||||
def dfplayer_stop_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_action('dfplayer.random', RandomAction, cv.Schema({
|
||||
cv.GenerateID(): cv.use_id(DFPlayer),
|
||||
}))
|
||||
def dfplayer_random_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_condition('dfplayer.is_playing', DFPlayerIsPlayingCondition, cv.Schema({
|
||||
cv.GenerateID(): cv.use_id(DFPlayer),
|
||||
}))
|
||||
def dfplyaer_is_playing_to_code(config, condition_id, template_arg, args):
|
||||
var = cg.new_Pvariable(condition_id, template_arg)
|
||||
yield cg.register_parented(var, config[CONF_ID])
|
||||
yield var
|
120
esphome/components/dfplayer/dfplayer.cpp
Normal file
120
esphome/components/dfplayer/dfplayer.cpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
#include "dfplayer.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace dfplayer {
|
||||
|
||||
static const char* TAG = "dfplayer";
|
||||
|
||||
void DFPlayer::play_folder(uint16_t folder, uint16_t file) {
|
||||
if (folder < 100 && file < 256) {
|
||||
this->send_cmd_(0x0F, (uint8_t) folder, (uint8_t) file);
|
||||
} else if (folder <= 10 && file <= 1000) {
|
||||
this->send_cmd_(0x14, (((uint16_t) folder) << 12) | file);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Cannot play folder %d file %d.", folder, file);
|
||||
}
|
||||
}
|
||||
|
||||
void DFPlayer::send_cmd_(uint8_t cmd, uint16_t argument) {
|
||||
uint8_t buffer[10]{0x7e, 0xff, 0x06, cmd, 0x01, (uint8_t)(argument >> 8), (uint8_t) argument, 0x00, 0x00, 0xef};
|
||||
uint16_t checksum = 0;
|
||||
for (uint8_t i = 1; i < 7; i++)
|
||||
checksum += buffer[i];
|
||||
checksum = -checksum;
|
||||
buffer[7] = checksum >> 8;
|
||||
buffer[8] = (uint8_t) checksum;
|
||||
|
||||
this->sent_cmd_ = cmd;
|
||||
|
||||
ESP_LOGD(TAG, "Send Command %#02x arg %#04x", cmd, argument);
|
||||
this->write_array(buffer, 10);
|
||||
}
|
||||
|
||||
void DFPlayer::loop() {
|
||||
// Read message
|
||||
while (this->available()) {
|
||||
uint8_t byte;
|
||||
this->read_byte(&byte);
|
||||
|
||||
if (this->read_pos_ == DFPLAYER_READ_BUFFER_LENGTH)
|
||||
this->read_pos_ = 0;
|
||||
|
||||
switch (this->read_pos_) {
|
||||
case 0: // Start mark
|
||||
if (byte != 0x7E)
|
||||
continue;
|
||||
break;
|
||||
case 1: // Version
|
||||
if (byte != 0xFF) {
|
||||
ESP_LOGW(TAG, "Expected Version 0xFF, got %#02x", byte);
|
||||
this->read_pos_ = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 2: // Buffer length
|
||||
if (byte != 0x06) {
|
||||
ESP_LOGW(TAG, "Expected Buffer length 0x06, got %#02x", byte);
|
||||
this->read_pos_ = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 9: // End byte
|
||||
if (byte != 0xEF) {
|
||||
ESP_LOGW(TAG, "Expected end byte 0xEF, got %#02x", byte);
|
||||
this->read_pos_ = 0;
|
||||
continue;
|
||||
}
|
||||
// Parse valid received command
|
||||
uint8_t cmd = this->read_buffer_[3];
|
||||
uint16_t argument = (this->read_buffer_[5] << 8) | this->read_buffer_[6];
|
||||
|
||||
ESP_LOGV(TAG, "Received message cmd: %#02x arg %#04x", cmd, argument);
|
||||
|
||||
switch (cmd) {
|
||||
case 0x3A:
|
||||
if (argument == 1) {
|
||||
ESP_LOGI(TAG, "USB loaded");
|
||||
} else if (argument == 2)
|
||||
ESP_LOGI(TAG, "TF Card loaded");
|
||||
break;
|
||||
case 0x3B:
|
||||
if (argument == 1) {
|
||||
ESP_LOGI(TAG, "USB unloaded");
|
||||
} else if (argument == 2)
|
||||
ESP_LOGI(TAG, "TF Card unloaded");
|
||||
break;
|
||||
case 0x3F:
|
||||
if (argument == 1) {
|
||||
ESP_LOGI(TAG, "USB available");
|
||||
} else if (argument == 2) {
|
||||
ESP_LOGI(TAG, "TF Card available");
|
||||
} else if (argument == 3) {
|
||||
ESP_LOGI(TAG, "USB, TF Card available");
|
||||
}
|
||||
break;
|
||||
case 0x41:
|
||||
ESP_LOGV(TAG, "Ack ok");
|
||||
this->is_playing_ |= this->ack_set_is_playing_;
|
||||
this->is_playing_ &= !this->ack_reset_is_playing_;
|
||||
this->ack_set_is_playing_ = false;
|
||||
this->ack_reset_is_playing_ = false;
|
||||
break;
|
||||
case 0x3D: // Playback finished
|
||||
this->is_playing_ = false;
|
||||
this->on_finished_playback_callback_.call();
|
||||
break;
|
||||
default:
|
||||
ESP_LOGD(TAG, "Command %#02x arg %#04x", cmd, argument);
|
||||
}
|
||||
this->sent_cmd_ = 0;
|
||||
this->read_pos_ = 0;
|
||||
continue;
|
||||
}
|
||||
this->read_buffer_[this->read_pos_] = byte;
|
||||
this->read_pos_++;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dfplayer
|
||||
} // namespace esphome
|
165
esphome/components/dfplayer/dfplayer.h
Normal file
165
esphome/components/dfplayer/dfplayer.h
Normal file
|
@ -0,0 +1,165 @@
|
|||
#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->send_cmd_(0x01); }
|
||||
void previous() { 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->send_cmd_(0x08, file); }
|
||||
void play_folder(uint16_t folder, uint16_t file);
|
||||
void play_folder_loop(uint16_t folder) { 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->send_cmd_(0x0A); }
|
||||
void reset() { this->send_cmd_(0x0C); }
|
||||
void start() { this->send_cmd_(0x0D); }
|
||||
void pause() {
|
||||
this->ack_reset_is_playing_ = true;
|
||||
this->send_cmd_(0x0E);
|
||||
}
|
||||
void stop() { this->send_cmd_(0x16); }
|
||||
void random() { this->send_cmd_(0x18); }
|
||||
|
||||
bool is_playing() { return is_playing_; }
|
||||
|
||||
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> { \
|
||||
public: \
|
||||
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
|
|
@ -60,6 +60,83 @@ api:
|
|||
- float_arr.size()
|
||||
- string_arr[0].c_str()
|
||||
- string_arr.size()
|
||||
- service: dfplayer_next
|
||||
then:
|
||||
- dfplayer.play_next:
|
||||
- service: dfplayer_previous
|
||||
then:
|
||||
- dfplayer.play_previous:
|
||||
- service: dfplayer_play
|
||||
variables:
|
||||
file: int
|
||||
then:
|
||||
- dfplayer.play: !lambda 'return file;'
|
||||
- service: dfplayer_play_loop
|
||||
variables:
|
||||
file: int
|
||||
loop_: bool
|
||||
then:
|
||||
- dfplayer.play:
|
||||
file: !lambda 'return file;'
|
||||
loop: !lambda 'return loop_;'
|
||||
- service: dfplayer_play_folder
|
||||
variables:
|
||||
folder: int
|
||||
file: int
|
||||
then:
|
||||
- dfplayer.play_folder:
|
||||
folder: !lambda 'return folder;'
|
||||
file: !lambda 'return file;'
|
||||
|
||||
- service: dfplayer_play_loo_folder
|
||||
variables:
|
||||
folder: int
|
||||
then:
|
||||
- dfplayer.play_folder:
|
||||
folder: !lambda 'return folder;'
|
||||
loop: True
|
||||
|
||||
- service: dfplayer_set_device
|
||||
variables:
|
||||
device: int
|
||||
then:
|
||||
- dfplayer.set_device:
|
||||
device: TF_CARD
|
||||
|
||||
- service: dfplayer_set_volume
|
||||
variables:
|
||||
volume: int
|
||||
then:
|
||||
- dfplayer.set_volume: !lambda 'return volume;'
|
||||
- service: dfplayer_set_eq
|
||||
variables:
|
||||
preset: int
|
||||
then:
|
||||
- dfplayer.set_eq: !lambda 'return static_cast<dfplayer::EqPreset>(preset);'
|
||||
|
||||
- service: dfplayer_sleep
|
||||
then:
|
||||
- dfplayer.sleep
|
||||
|
||||
- service: dfplayer_reset
|
||||
then:
|
||||
- dfplayer.reset
|
||||
|
||||
- service: dfplayer_start
|
||||
then:
|
||||
- dfplayer.start
|
||||
|
||||
- service: dfplayer_pause
|
||||
then:
|
||||
- dfplayer.pause
|
||||
|
||||
- service: dfplayer_stop
|
||||
then:
|
||||
- dfplayer.stop
|
||||
|
||||
- service: dfplayer_random
|
||||
then:
|
||||
- dfplayer.random
|
||||
|
||||
wifi:
|
||||
ssid: 'MySSID'
|
||||
|
@ -532,3 +609,13 @@ sim800l:
|
|||
- sim800l.send_sms:
|
||||
message: 'hello you'
|
||||
recipient: '+1234'
|
||||
|
||||
dfplayer:
|
||||
on_finished_playback:
|
||||
then:
|
||||
if:
|
||||
condition:
|
||||
not:
|
||||
dfplayer.is_playing
|
||||
then:
|
||||
logger.log: 'Playback finished event'
|
||||
|
|
Loading…
Reference in a new issue