mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-28 04:07:47 +00:00
Merge branch 'mega' of https://github.com/letscontrolit/ESPEasy into feature/p008-add-option-for-reversed-decoding
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
.. include:: ../Plugin/_plugin_substitutions_p06x.repl
|
||||
.. include:: ../Plugin/_plugin_substitutions_p06x.repl
|
||||
.. _P065_page:
|
||||
|
||||
|P065_typename|
|
||||
@@ -21,15 +21,93 @@ Maintainer: |P065_maintainer|
|
||||
|
||||
Used libraries: |P065_usedlibraries|
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The ESP module can control the MP3-player module "DRPlayer Mini (DFR0299/YX5200)" and the "YX5300" module with 3.5mm output for speaker(s). Other than MP3 (sampling frequencies up to 48kHz) WAV files are also supported. The file names can be whatever but if you would like to be sure to play the correct file you should use the following name schema:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
0000.mp3, 0001.mp3, 0002.mp3, 0003.mp3 ... 2998.mp3, 2999.mp3
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
.. image:: P065_DeviceConfiguration.png
|
||||
|
||||
**Name** In the Name field a unique name should be entered.
|
||||
|
||||
**Enabled** When unchecked the plugin is not enabled.
|
||||
|
||||
**GPIO - RX** The GPIO pin that is wired to the player' RX pin. No information can be retrieved from the unit, so no connection to TX is needed.
|
||||
|
||||
**Volume** The default volume setting at startup. When using the ``vol`` command, this value will be updated, but not saved. When opening the configuration, and saving the settings, it *will* be saved though. Also, using the ``save`` command will save the setting once changed by the ``vol`` command.
|
||||
|
||||
Supported hardware
|
||||
------------------
|
||||
|
||||
:ref:`P065_DFPlayer_Mini_page`
|
||||
|
||||
.. image:: P065_DFPlayer-Mini-MP3-Player.jpg
|
||||
|
||||
|
||||
:ref:`P065_YX5300_page`
|
||||
|
||||
.. image:: P065_YX5300-MP3-Player.jpg
|
||||
|
||||
|
||||
|P065_usedby|
|
||||
|
||||
.. Commands available
|
||||
.. ^^^^^^^^^^^^^^^^^^
|
||||
Commands available
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. .. include:: P065_commands.repl
|
||||
.. include:: P065_commands.repl
|
||||
|
||||
How to play a track
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
HTTP
|
||||
====
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
http://<ESP IP address>/control?cmd=play,14
|
||||
|
||||
This plays track number 14. The song will be stopped once completed, unless repeat is enabled.
|
||||
|
||||
Rules
|
||||
=====
|
||||
|
||||
To start playing a song at startup of the ESP for 30 seconds, these rules can be added:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
On System#Boot do
|
||||
vol,10
|
||||
play,255 // file number 255
|
||||
timerSet,1,30 //play the song for 30 seconds (this is a generic command!)
|
||||
Endon
|
||||
|
||||
On Rules#Timer=1 do
|
||||
Stop
|
||||
Endon
|
||||
|
||||
MQTT
|
||||
====
|
||||
|
||||
Topic:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
<unit name>/cmd
|
||||
|
||||
Payload/message:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
play,188
|
||||
|
||||
This will play the song number 188.
|
||||
|
||||
.. Events
|
||||
.. ~~~~~~
|
||||
@@ -40,7 +118,13 @@ Change log
|
||||
----------
|
||||
|
||||
.. versionchanged:: 2.0
|
||||
...
|
||||
...
|
||||
|
||||
|improved| 2021-05-01
|
||||
Moved (most) documentation to new format from the wiki.
|
||||
|
||||
|added| 2021-05-01
|
||||
Added ``mode`` and ``repeat`` commands
|
||||
|
||||
|added|
|
||||
Major overhaul for 2.0 release.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -1,11 +1,11 @@
|
||||
.. include:: ../Plugin/_plugin_substitutions_p06x.repl
|
||||
.. .. include:: ../Plugin/_plugin_substitutions_p06x.repl
|
||||
.. _P065_DFPlayer_Mini_page:
|
||||
|
||||
DFPlayer Mini
|
||||
=============
|
||||
|
||||
|P065_typename|
|
||||
|P065_status|
|
||||
.. .. |P065_typename|
|
||||
.. .. |P065_status|
|
||||
|
||||
|
||||
Introduction
|
||||
@@ -22,37 +22,52 @@ Wiring
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
ESP S8
|
||||
GPIO (X) <--> TX
|
||||
GPIO (X) <--> RX
|
||||
ESP MP3-player
|
||||
GPIO (X) <--> RX*
|
||||
|
||||
|
||||
Power
|
||||
5.0V <--> VCC
|
||||
GND <--> GND
|
||||
5.0V or 3.3V <--> VCC
|
||||
GND <--> GND
|
||||
|
||||
Speaker
|
||||
Red <--> SPK_1
|
||||
Black <--> SPK_2
|
||||
|
||||
Setup
|
||||
-----
|
||||
Other
|
||||
IO_1 <--> Button, short press: previous track, long press: decrease volume
|
||||
IO_2 <--> Button, short press: next track, long press: increase volume
|
||||
|
||||
LED
|
||||
LED** <--> BUSY
|
||||
|
||||
\*note that the TX on the mp3-module is not used!
|
||||
|
||||
Rules examples
|
||||
--------------
|
||||
\*\*optional, if you want a LED to indicate playback (low active).
|
||||
|
||||
.. code-block:: none
|
||||
.. image:: P065_miniplayer_pin_map.png
|
||||
|
||||
//Code below...
|
||||
|
||||
|
||||
Indicators (recommended settings)
|
||||
---------------------------------
|
||||
|
||||
.. csv-table::
|
||||
:header: "Indicator", "Value Name", "Interval", "Decimals", "Extra information"
|
||||
:widths: 8, 5, 5, 5, 40
|
||||
|
||||
"XXXXXX", "N/A", "", "", ""
|
||||
.. Setup
|
||||
.. -----
|
||||
..
|
||||
..
|
||||
..
|
||||
.. Rules examples
|
||||
.. --------------
|
||||
..
|
||||
.. .. code-block:: none
|
||||
..
|
||||
.. //Code below...
|
||||
..
|
||||
..
|
||||
.. Indicators (recommended settings)
|
||||
.. ---------------------------------
|
||||
..
|
||||
.. .. csv-table::
|
||||
.. :header: "Indicator", "Value Name", "Interval", "Decimals", "Extra information"
|
||||
.. :widths: 8, 5, 5, 5, 40
|
||||
..
|
||||
.. "XXXXXX", "N/A", "", "", ""
|
||||
|
||||
Where to buy
|
||||
------------
|
||||
@@ -66,5 +81,5 @@ Where to buy
|
||||
|affiliate|
|
||||
|
||||
|
||||
More pictures
|
||||
-------------
|
||||
.. More pictures
|
||||
.. -------------
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
@@ -1,11 +1,11 @@
|
||||
.. include:: ../Plugin/_plugin_substitutions_p06x.repl
|
||||
.. .. include:: ../Plugin/_plugin_substitutions_p06x.repl
|
||||
.. _P065_YX5300_page:
|
||||
|
||||
YX5300
|
||||
======
|
||||
|
||||
|P065_typename|
|
||||
|P065_status|
|
||||
.. .. |P065_typename|
|
||||
.. .. |P065_status|
|
||||
|
||||
|
||||
Introduction
|
||||
@@ -22,37 +22,36 @@ Wiring
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
ESP S8
|
||||
GPIO (X) <--> TX
|
||||
GPIO (X) <--> RX
|
||||
ESP S8
|
||||
GPIO (X) <--> RX
|
||||
|
||||
|
||||
Power
|
||||
5.0V <--> VCC
|
||||
GND <--> GND
|
||||
5.0V or 3.3V <--> VCC
|
||||
GND <--> GND
|
||||
|
||||
|
||||
Setup
|
||||
-----
|
||||
.. Setup
|
||||
.. -----
|
||||
..
|
||||
..
|
||||
..
|
||||
.. Rules examples
|
||||
.. --------------
|
||||
..
|
||||
.. .. code-block:: none
|
||||
..
|
||||
.. //Code below...
|
||||
|
||||
|
||||
|
||||
Rules examples
|
||||
--------------
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
//Code below...
|
||||
|
||||
|
||||
Indicators (recommended settings)
|
||||
---------------------------------
|
||||
|
||||
.. csv-table::
|
||||
:header: "Indicator", "Value Name", "Interval", "Decimals", "Extra information"
|
||||
:widths: 8, 5, 5, 5, 40
|
||||
|
||||
"XXXXXX", "N/A", "", "", ""
|
||||
.. Indicators (recommended settings)
|
||||
.. ---------------------------------
|
||||
..
|
||||
.. .. csv-table::
|
||||
.. :header: "Indicator", "Value Name", "Interval", "Decimals", "Extra information"
|
||||
.. :widths: 8, 5, 5, 5, 40
|
||||
..
|
||||
.. "XXXXXX", "N/A", "", "", ""
|
||||
|
||||
Where to buy
|
||||
------------
|
||||
@@ -66,5 +65,5 @@ Where to buy
|
||||
|affiliate|
|
||||
|
||||
|
||||
More pictures
|
||||
-------------
|
||||
.. More pictures
|
||||
.. -------------
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
.. csv-table::
|
||||
:header: "Command", "Extra information"
|
||||
:widths: 20, 30
|
||||
|
||||
"
|
||||
``play,<number>``
|
||||
|
||||
Example:
|
||||
|
||||
``play,12`` to play the 12th track available on the SD card.
|
||||
|
||||
","
|
||||
Starts playing the nth file on the SD-card. Acceptable numbers 0..2999.
|
||||
"
|
||||
"
|
||||
``stop``
|
||||
|
||||
","
|
||||
Stops playing the current file immediately.
|
||||
"
|
||||
"
|
||||
``vol,<volume>``
|
||||
|
||||
Example:
|
||||
|
||||
``vol,15``
|
||||
|
||||
","
|
||||
Change the playback volume to the set level. Acceptable values 1..30. When 0 (or no argument) is provided, the max. volume will be set!
|
||||
|
||||
Volume is also stored in the settings, but not saved untile either a ``save`` command is used, or the settings of the device is saved from the web interface.
|
||||
"
|
||||
"
|
||||
``eq,<type>``
|
||||
|
||||
Example:
|
||||
|
||||
``eq,4``
|
||||
|
||||
","
|
||||
Select the equalizer configuration. Acceptable values 0..5.
|
||||
|
||||
0 = Normal
|
||||
|
||||
1 = Pop
|
||||
|
||||
2 = Rock
|
||||
|
||||
3 = Classic
|
||||
|
||||
4 = Jazz
|
||||
|
||||
5 = Base
|
||||
"
|
||||
"
|
||||
``mode,<mode>``
|
||||
|
||||
Example:
|
||||
|
||||
``mode,3``
|
||||
|
||||
","
|
||||
Select the playback mode. Acceptable values 0..3.
|
||||
|
||||
0 = Repeat
|
||||
|
||||
1 = Folder repeat
|
||||
|
||||
2 = Single repeat
|
||||
|
||||
3 = Random
|
||||
|
||||
NB: To have actual repeat playing a track, the ``repeat`` command should also be enabled.
|
||||
|
||||
NB2: This command does not work on all players, it may start a ``play,<mode>`` with repeat enabled instead. That seems hardware related.
|
||||
"
|
||||
"
|
||||
``repeat,<0|1>``
|
||||
|
||||
Example:
|
||||
|
||||
``repeat,1``
|
||||
","
|
||||
To set repeat mode. Default is off, acceptable values 0 or 1.
|
||||
|
||||
0 = Off
|
||||
|
||||
1 = On
|
||||
"
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
@@ -72,7 +72,7 @@
|
||||
.. _P065_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P065_DRF0299_MP3.ino
|
||||
.. |P065_usedby| replace:: `.`
|
||||
.. |P065_shortinfo| replace:: `.`
|
||||
.. |P065_maintainer| replace:: `.`
|
||||
.. |P065_maintainer| replace:: `TD-er, JK-de, tonhuisman`
|
||||
.. |P065_compileinfo| replace:: `.`
|
||||
.. |P065_usedlibraries| replace:: `.`
|
||||
|
||||
|
||||
@@ -506,10 +506,10 @@ P052 :ref:`P052_page`
|
||||
.. .. include:: ../Plugin/P064_commands.repl
|
||||
|
||||
|
||||
.. P065 :ref:`P065_page`
|
||||
.. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
P065 :ref:`P065_page`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. .. include:: ../Plugin/P065_commands.repl
|
||||
.. include:: ../Plugin/P065_commands.repl
|
||||
|
||||
|
||||
.. P066 :ref:`P066_page`
|
||||
|
||||
@@ -119,6 +119,8 @@ Supported RTC chips:
|
||||
Most modules sold with one of these RTC chips also have a battery socket to keep track of time while the rest is not powered.
|
||||
This allows ESPEasy to know the correct date and time after been powered off for a while, or deep sleep, without the need for working network to query a NTP server.
|
||||
|
||||
N.B. these modules all use I2C, so they need to be connected to the configured I2C pins and those pins should be set.
|
||||
|
||||
DST Settings
|
||||
------------
|
||||
|
||||
@@ -208,6 +210,19 @@ JSON bool output without quotes
|
||||
|
||||
ESPEasy JSON output has always used quoted bool values, ``"true"`` and ``"false"``, that are in fact string values. According to JSON standards, bool values should be ``true`` and ``false``, so this setting selects what type of bool values will be emitted. As existing functionality is to be left unaltered/backward compatible as much as possible, by default this setting is unchecked.
|
||||
|
||||
Allow TaskValueSet on all plugins
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Added: 2021-08-06
|
||||
|
||||
The command TaskValueSet was never intended to be used on any other then a 'dummy' task.
|
||||
However it appeared there are some use cases where it may be useful to use TaskValueSet on other types of tasks.
|
||||
|
||||
To use it on other then a 'dummy' task, this option must be checked.
|
||||
|
||||
Default: unchecked
|
||||
|
||||
|
||||
|
||||
Deep Sleep Alternative
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
+1023
-825
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -89,7 +89,7 @@ boolean Plugin_040(uint8_t function, struct EventStruct *event, String& string)
|
||||
}
|
||||
|
||||
// Do Ascii/Hex conversion:
|
||||
if ((val >= '0') && (val <= '9')) {
|
||||
if (isDigit(val)) {
|
||||
val = val - '0';
|
||||
}
|
||||
else if ((val >= 'A') && (val <= 'F')) {
|
||||
|
||||
+173
-134
@@ -1,25 +1,33 @@
|
||||
#include "_Plugin_Helper.h"
|
||||
#ifdef USES_P065
|
||||
//#######################################################################################################
|
||||
//############################# Plugin 065: P065_DFR0299_MP3 ############################################
|
||||
//#######################################################################################################
|
||||
|
||||
// #######################################################################################################
|
||||
// ############################# Plugin 065: P065_DFR0299_MP3 ############################################
|
||||
// #######################################################################################################
|
||||
|
||||
// ESPEasy Plugin to controls a MP3-player-module DFPlayer-Mini SKU:DFR0299
|
||||
// written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
// Change history:
|
||||
// 2021-05-01, tonhuisman: Add mode and repeat commands, optimize string and log usage to reduce size
|
||||
|
||||
// Important! The module WTV020-SD look similar to the module DFPlayer-Mini but is NOT pin nor command compatible!
|
||||
|
||||
// Commands:
|
||||
// play,<track> Plays the n-th track 1...3000 on SD-card in root folder. The track number is the physical order - not the order displayed in file explorer!
|
||||
// play,<track> Plays the n-th track 1...3000 on SD-card in root folder. The track number is the physical order - not the order
|
||||
// displayed in file explorer!
|
||||
// stop Stops actual playing sound
|
||||
// vol,<volume> Set volume level 1...30
|
||||
// eq,<type> Set the equalizer type 0=Normal, 1=Pop, 2=Rock, 3=Jazz, 4=classic, 5=Base
|
||||
// mode,<mode> Set the playback mode 0=Repeat, 1=Folder repeat, 2=Single repeat, 3=Random
|
||||
// repeat,<0/1> Set repeat mode 0=Off, 1=On
|
||||
|
||||
// Circuit wiring
|
||||
// 1st-GPIO -> ESP TX to module RX [Pin2]
|
||||
// 5 V to module VCC [Pin1] (can be more than 100 mA) Note: Use a blocking capacitor to stabilise VCC
|
||||
// GND to module GND [Pin7+Pin10]
|
||||
// Speaker to module SPK_1 and SPK_2 [Pin6,Pin8] (not to GND!) Note: If speaker has to low impedance, use a resistor (like 33 Ohm) in line to speaker
|
||||
// Speaker to module SPK_1 and SPK_2 [Pin6,Pin8] (not to GND!) Note: If speaker has to low impedance, use a resistor (like 33 Ohm) in line
|
||||
// to speaker
|
||||
// (optional) module BUSY [Pin16] to LED driver (3.3 V on idle, 0 V on playing)
|
||||
// All other pins unconnected
|
||||
|
||||
@@ -28,17 +36,15 @@
|
||||
// Datasheet: https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299
|
||||
|
||||
|
||||
# define PLUGIN_065
|
||||
# define PLUGIN_ID_065 65
|
||||
# define PLUGIN_NAME_065 "Notify - DFPlayer-Mini MP3 [TESTING]"
|
||||
# define PLUGIN_VALUENAME1_065 ""
|
||||
|
||||
#define PLUGIN_065
|
||||
#define PLUGIN_ID_065 65
|
||||
#define PLUGIN_NAME_065 "Notify - DFPlayer-Mini MP3 [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_065 ""
|
||||
|
||||
#include <ESPeasySerial.h>
|
||||
# include <ESPeasySerial.h>
|
||||
|
||||
|
||||
|
||||
ESPeasySerial* P065_easySerial = NULL;
|
||||
ESPeasySerial *P065_easySerial = NULL;
|
||||
|
||||
|
||||
boolean Plugin_065(uint8_t function, struct EventStruct *event, String& string)
|
||||
@@ -47,177 +53,210 @@ boolean Plugin_065(uint8_t function, struct EventStruct *event, String& string)
|
||||
|
||||
switch (function)
|
||||
{
|
||||
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_065;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
|
||||
Device[deviceCount].VType = Sensor_VType::SENSOR_TYPE_NONE;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 0;
|
||||
Device[deviceCount].SendDataOption = false;
|
||||
Device[deviceCount].TimerOption = false;
|
||||
Device[deviceCount].GlobalSyncOption = false;
|
||||
break;
|
||||
}
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_065;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
|
||||
Device[deviceCount].VType = Sensor_VType::SENSOR_TYPE_NONE;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 0;
|
||||
Device[deviceCount].SendDataOption = false;
|
||||
Device[deviceCount].TimerOption = false;
|
||||
Device[deviceCount].GlobalSyncOption = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_065);
|
||||
break;
|
||||
}
|
||||
{
|
||||
string = F(PLUGIN_NAME_065);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEGPIONAMES:
|
||||
{
|
||||
event->String1 = formatGpioName_TX(false);
|
||||
break;
|
||||
}
|
||||
case PLUGIN_GET_DEVICEGPIONAMES:
|
||||
{
|
||||
event->String1 = formatGpioName_TX(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
addFormNumericBox(F("Volume"), F("volume"), PCONFIG(0), 1, 30);
|
||||
{
|
||||
addFormNumericBox(F("Volume"), F("volume"), PCONFIG(0), 1, 30);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
PCONFIG(0) = getFormItemInt(F("volume"));
|
||||
{
|
||||
PCONFIG(0) = getFormItemInt(F("volume"));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
//note: we cant fix this, its a upstream bug.
|
||||
#pragma GCC diagnostic warning "-Wdelete-non-virtual-dtor"
|
||||
if (P065_easySerial)
|
||||
delete P065_easySerial;
|
||||
#pragma GCC diagnostic pop
|
||||
{
|
||||
# pragma GCC diagnostic push
|
||||
|
||||
// note: we cant fix this, its a upstream bug.
|
||||
# pragma GCC diagnostic warning "-Wdelete-non-virtual-dtor"
|
||||
|
||||
P065_easySerial = new (std::nothrow) ESPeasySerial(static_cast<ESPEasySerialPort>(CONFIG_PORT), -1, CONFIG_PIN1); // no RX, only TX
|
||||
if (P065_easySerial != nullptr) {
|
||||
P065_easySerial->begin(9600);
|
||||
Plugin_065_SetVol(PCONFIG(0)); // set default volume
|
||||
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
if (P065_easySerial) {
|
||||
delete P065_easySerial;
|
||||
}
|
||||
# pragma GCC diagnostic pop
|
||||
|
||||
|
||||
P065_easySerial = new (std::nothrow) ESPeasySerial(static_cast<ESPEasySerialPort>(CONFIG_PORT), -1, CONFIG_PIN1); // no RX, only TX
|
||||
|
||||
if (P065_easySerial != nullptr) {
|
||||
P065_easySerial->begin(9600);
|
||||
Plugin_065_SetVol(PCONFIG(0)); // set default volume
|
||||
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
if (!P065_easySerial)
|
||||
break;
|
||||
|
||||
String command = parseString(string, 1);
|
||||
String param = parseString(string, 2);
|
||||
|
||||
if (command == F("play"))
|
||||
{
|
||||
int track;
|
||||
if (validIntFromString(param, track)) {
|
||||
Plugin_065_Play(track);
|
||||
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
|
||||
String log = F("MP3 : play=");
|
||||
log += track;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (command == F("stop"))
|
||||
{
|
||||
Plugin_065_SendCmd(0x0E, 0);
|
||||
|
||||
addLog(LOG_LEVEL_INFO, F("MP3 : stop"));
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (command == F("vol"))
|
||||
{
|
||||
String log = F("MP3 : vol=");
|
||||
|
||||
int8_t vol = param.toInt();
|
||||
if (vol == 0) vol = 30;
|
||||
PCONFIG(0) = vol;
|
||||
Plugin_065_SetVol(vol);
|
||||
log += vol;
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (command == F("eq"))
|
||||
{
|
||||
String log = F("MP3 : eq=");
|
||||
|
||||
int8_t eq = param.toInt();
|
||||
Plugin_065_SetEQ(eq);
|
||||
log += eq;
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
}
|
||||
|
||||
{
|
||||
if (!P065_easySerial) {
|
||||
break;
|
||||
}
|
||||
|
||||
String command = parseString(string, 1);
|
||||
String param = parseString(string, 2);
|
||||
int value;
|
||||
bool valueValid = validIntFromString(param, value);
|
||||
|
||||
if (valueValid && (command == F("play")))
|
||||
{
|
||||
Plugin_065_Play(value);
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (command == F("stop"))
|
||||
{
|
||||
Plugin_065_SendCmd(0x0E, 0);
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (valueValid && (command == F("vol")))
|
||||
{
|
||||
if (value == 0) { value = 30; }
|
||||
PCONFIG(0) = value;
|
||||
Plugin_065_SetVol(value);
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (valueValid && (command == F("eq")))
|
||||
{
|
||||
Plugin_065_SetEQ(value);
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (valueValid && (command == F("mode")))
|
||||
{
|
||||
Plugin_065_SetMode(value);
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (valueValid && (command == F("repeat")))
|
||||
{
|
||||
Plugin_065_SetRepeat(value);
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (success && loglevelActiveFor(LOG_LEVEL_INFO)) {
|
||||
String log;
|
||||
log.reserve(20);
|
||||
log = F("MP3 : ");
|
||||
log += command;
|
||||
|
||||
if (command != F("stop")) {
|
||||
log += '=';
|
||||
log += value;
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
void Plugin_065_Play(uint16_t track)
|
||||
{
|
||||
if (track < 0) { track = 0; }
|
||||
|
||||
if (track > 2999) { track = 2999; }
|
||||
|
||||
Plugin_065_SendCmd(0x03, track);
|
||||
}
|
||||
|
||||
void Plugin_065_SetVol(int8_t vol)
|
||||
{
|
||||
if (vol < 1) vol = 1;
|
||||
if (vol > 30) vol = 30;
|
||||
if (vol < 1) { vol = 1; }
|
||||
|
||||
if (vol > 30) { vol = 30; }
|
||||
|
||||
Plugin_065_SendCmd(0x06, vol);
|
||||
}
|
||||
|
||||
void Plugin_065_SetEQ(int8_t eq)
|
||||
{
|
||||
if (eq < 0) eq = 0;
|
||||
if (eq > 5) eq = 5;
|
||||
if (eq < 0) { eq = 0; }
|
||||
|
||||
if (eq > 5) { eq = 5; }
|
||||
|
||||
Plugin_065_SendCmd(0x07, eq);
|
||||
}
|
||||
|
||||
void Plugin_065_SetMode(int8_t mode)
|
||||
{
|
||||
if (mode < 0) { mode = 0; }
|
||||
|
||||
if (mode > 3) { mode = 3; }
|
||||
|
||||
Plugin_065_SendCmd(0x08, mode);
|
||||
}
|
||||
|
||||
void Plugin_065_SetRepeat(int8_t repeat)
|
||||
{
|
||||
Plugin_065_SendCmd(0x11, (repeat <= 0) ? 0 : 1);
|
||||
}
|
||||
|
||||
void Plugin_065_SendCmd(uint8_t cmd, int16_t data)
|
||||
{
|
||||
if (!P065_easySerial)
|
||||
if (!P065_easySerial) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t buffer[10] = { 0x7E, 0xFF, 0x06, 0, 0x00, 0, 0, 0, 0, 0xEF };
|
||||
|
||||
buffer[3] = cmd;
|
||||
buffer[5] = data >> 8; // high uint8_t
|
||||
buffer[6] = data & 0xFF; // low uint8_t
|
||||
buffer[5] = data >> 8; // high byte
|
||||
buffer[6] = data & 0xFF; // low byte
|
||||
|
||||
int16_t checksum = -(buffer[1] + buffer[2] + buffer[3] + buffer[4] + buffer[5] + buffer[6]);
|
||||
buffer[7] = checksum >> 8; // high uint8_t
|
||||
buffer[8] = checksum & 0xFF; // low uint8_t
|
||||
|
||||
P065_easySerial->write(buffer, 10); //Send the uint8_t array
|
||||
buffer[7] = checksum >> 8; // high byte
|
||||
buffer[8] = checksum & 0xFF; // low byte
|
||||
|
||||
String log = F("MP3 : Send Cmd ");
|
||||
for (uint8_t i=0; i<10; i++)
|
||||
{
|
||||
log += String(buffer[i], 16);
|
||||
log += ' ';
|
||||
P065_easySerial->write(buffer, 10); // Send the byte array
|
||||
|
||||
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
|
||||
String log = F("MP3 : Send Cmd ");
|
||||
|
||||
for (uint8_t i = 0; i < 10; i++) {
|
||||
log += String(buffer[i], 16);
|
||||
log += ' ';
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
}
|
||||
|
||||
#endif // USES_P065
|
||||
|
||||
+6
-10
@@ -576,12 +576,10 @@ uint8_t P073_mapCharToFontPosition(char character, uint8_t fontset) {
|
||||
case 2: // Siekoo with uppercase 'CHNORUX'
|
||||
if (fontset == 2 && chnorux.indexOf(character) > -1) {
|
||||
position = chnorux.indexOf(character) + 35;
|
||||
} else if ((character >= '0') && (character <= '9')) {
|
||||
} else if (isDigit(character)) {
|
||||
position = character - '0';
|
||||
} else if ((character >= 'A') && (character <= 'Z')) {
|
||||
position = character - 'A' + 42;
|
||||
} else if ((character >= 'a') && (character <= 'z')) {
|
||||
position = character - 'a' + 42;
|
||||
} else if (isAlpha(character)) {
|
||||
position = character - (isLowerCase(character) ? 'a' : 'A') + 42;
|
||||
} else {
|
||||
uint8_t idx = specialChars.indexOf(character);
|
||||
if (idx > -1) {
|
||||
@@ -592,12 +590,10 @@ uint8_t P073_mapCharToFontPosition(char character, uint8_t fontset) {
|
||||
case 3: // dSEG7 (same table size as 7Dgt)
|
||||
default: // Original fontset (7Dgt)
|
||||
#endif // P073_EXTRA_FONTS
|
||||
if ((character >= '0') && (character <= '9')) {
|
||||
if (isDigit(character)) {
|
||||
position = character - '0';
|
||||
} else if ((character >= 'A') && (character <= 'Z')) {
|
||||
position = character - 'A' + 16;
|
||||
} else if ((character >= 'a') && (character <= 'z')) {
|
||||
position = character - 'a' + 16;
|
||||
} else if (isAlpha(character)) {
|
||||
position = character - (isLowerCase(character) ? 'a' : 'A') + 16;
|
||||
} else {
|
||||
switch (character) {
|
||||
case ' ': position = 10; break;
|
||||
|
||||
@@ -79,7 +79,7 @@ const __FlashStringHelper * taskValueSet(struct EventStruct *event, const char *
|
||||
success = false;
|
||||
return F("INVALID_PARAMETERS");
|
||||
}
|
||||
if (getPluginID_from_TaskIndex(taskIndex) != 33) { // PluginID 33 = Dummy Device
|
||||
if (!Settings.AllowTaskValueSetAllPlugins() && getPluginID_from_TaskIndex(taskIndex) != 33) { // PluginID 33 = Dummy Device
|
||||
success = false;
|
||||
return F("NOT_A_DUMMY_TASK");
|
||||
}
|
||||
|
||||
@@ -236,7 +236,15 @@ void SettingsStruct_tmpl<N_TASKS>::EnableTimingStats(bool value) {
|
||||
bitWrite(VariousBits1, 20, value);
|
||||
}
|
||||
|
||||
template<unsigned int N_TASKS>
|
||||
bool SettingsStruct_tmpl<N_TASKS>::AllowTaskValueSetAllPlugins() const {
|
||||
return bitRead(VariousBits1, 21);
|
||||
}
|
||||
|
||||
template<unsigned int N_TASKS>
|
||||
void SettingsStruct_tmpl<N_TASKS>::AllowTaskValueSetAllPlugins(bool value) {
|
||||
bitWrite(VariousBits1, 21, value);
|
||||
}
|
||||
|
||||
template<unsigned int N_TASKS>
|
||||
ExtTimeSource_e SettingsStruct_tmpl<N_TASKS>::ExtTimeSource() const {
|
||||
|
||||
@@ -137,6 +137,9 @@ class SettingsStruct_tmpl
|
||||
bool UseNTP() const;
|
||||
void UseNTP(bool value);
|
||||
|
||||
bool AllowTaskValueSetAllPlugins() const;
|
||||
void AllowTaskValueSetAllPlugins(bool value);
|
||||
|
||||
|
||||
void validate();
|
||||
|
||||
|
||||
@@ -167,8 +167,44 @@ String NetworkCreateRFCCompliantHostname(bool force_add_unitnr) {
|
||||
String createRFCCompliantHostname(const String& oldString) {
|
||||
String result(oldString);
|
||||
|
||||
result.replace(' ', '-');
|
||||
result.replace('_', '-'); // See RFC952
|
||||
// See RFC952.
|
||||
// Allowed chars:
|
||||
// * letters (a-z, A-Z)
|
||||
// * numerals (0-9)
|
||||
// * Hyphen (-)
|
||||
replaceUnicodeByChar(result, '-');
|
||||
for (size_t i = 0; i < result.length(); ++i) {
|
||||
const char c = result[i];
|
||||
if (!isAlphaNumeric(c)) {
|
||||
result[i] = '-';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// May not start or end with a hyphen
|
||||
while (result.startsWith(String('-'))) {
|
||||
result = result.substring(1);
|
||||
}
|
||||
while (result.endsWith(String('-'))) {
|
||||
result = result.substring(0, result.length() - 1);
|
||||
}
|
||||
|
||||
// May not contain only numerals
|
||||
bool onlyNumerals = true;
|
||||
for (size_t i = 0; onlyNumerals && i < result.length(); ++i) {
|
||||
const char c = result[i];
|
||||
if (!isdigit(c)) {
|
||||
onlyNumerals = false;
|
||||
}
|
||||
}
|
||||
if (onlyNumerals) {
|
||||
result = String(F("ESPEasy-")) + result;
|
||||
}
|
||||
|
||||
if (result.length() > 24) {
|
||||
result = result.substring(0, 24);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ unsigned long string2TimeLong(const String& str)
|
||||
{
|
||||
w = TmpStr1[x];
|
||||
|
||||
if (((w >= '0') && (w <= '9')) || (w == '*'))
|
||||
if (isDigit(w) || (w == '*'))
|
||||
{
|
||||
a = 0xffffffff ^ (0xfUL << y); // create mask to clean nibble position y
|
||||
lngTime &= a; // maak nibble leeg
|
||||
|
||||
@@ -222,6 +222,48 @@ void addNewLine(String& line) {
|
||||
line += F("\r\n");
|
||||
}
|
||||
|
||||
size_t UTF8_charLength(char firstByte) {
|
||||
if (firstByte <= 0x7f) {
|
||||
return 1;
|
||||
}
|
||||
// First Byte Second Byte Third Byte Fourth Byte
|
||||
// [0x00,0x7F]
|
||||
// [0xC2,0xDF] [0x80,0xBF]
|
||||
// 0xE0 [0xA0,0xBF] [0x80,0xBF]
|
||||
// [0xE1,0xEC] [0x80,0xBF] [0x80,0xBF]
|
||||
// 0xED [0x80,0x9F] [0x80,0xBF]
|
||||
// [0xEE,0xEF] [0x80,0xBF] [0x80,0xBF]
|
||||
// 0xF0 [0x90,0xBF] [0x80,0xBF] [0x80,0xBF]
|
||||
// [0xF1,0xF3] [0x80,0xBF] [0x80,0xBF] [0x80,0xBF]
|
||||
// 0xF4 [0x80,0x8F] [0x80,0xBF] [0x80,0xBF]
|
||||
// See: https://lemire.me/blog/2018/05/09/how-quickly-can-you-check-that-a-string-is-valid-unicode-utf-8/
|
||||
|
||||
size_t charLength = 2;
|
||||
if (firstByte > 0xEF) {
|
||||
charLength = 4;
|
||||
} else if (firstByte > 0xDF) {
|
||||
charLength = 3;
|
||||
}
|
||||
return charLength;
|
||||
}
|
||||
|
||||
void replaceUnicodeByChar(String& line, char replChar) {
|
||||
size_t pos = 0;
|
||||
while (pos < line.length()) {
|
||||
const size_t charLength = UTF8_charLength(line[pos]);
|
||||
|
||||
if (charLength > 1) {
|
||||
// Is unicode char in UTF-8 format
|
||||
// Need to find how many characters we need to replace.
|
||||
const size_t charsLeft = line.length() - pos;
|
||||
if (charsLeft >= charLength) {
|
||||
line.replace(line.substring(pos, pos + charLength), String(replChar));
|
||||
}
|
||||
}
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Format a value to the set number of decimals
|
||||
\*********************************************************************************************/
|
||||
@@ -626,7 +668,7 @@ void htmlStrongEscape(String& html)
|
||||
|
||||
for (unsigned i = 0; i < html.length(); ++i)
|
||||
{
|
||||
if (((html[i] >= 'a') && (html[i] <= 'z')) || ((html[i] >= 'A') && (html[i] <= 'Z')) || ((html[i] >= '0') && (html[i] <= '9')))
|
||||
if (isAlphaNumeric(html[i]))
|
||||
{
|
||||
escaped += html[i];
|
||||
}
|
||||
@@ -654,9 +696,7 @@ String URLEncode(const char *msg)
|
||||
encodedMsg.reserve(strlen(msg));
|
||||
|
||||
while (*msg != '\0') {
|
||||
if ((('a' <= *msg) && (*msg <= 'z'))
|
||||
|| (('A' <= *msg) && (*msg <= 'Z'))
|
||||
|| (('0' <= *msg) && (*msg <= '9'))
|
||||
if (isAlphaNumeric(*msg)
|
||||
|| ('-' == *msg) || ('_' == *msg)
|
||||
|| ('.' == *msg) || ('~' == *msg)) {
|
||||
encodedMsg += *msg;
|
||||
|
||||
@@ -83,6 +83,10 @@ void removeExtraNewLine(String& line);
|
||||
|
||||
void addNewLine(String& line);
|
||||
|
||||
size_t UTF8_charLength(char firstByte);
|
||||
|
||||
void replaceUnicodeByChar(String& line, char replChar);
|
||||
|
||||
/*********************************************************************************************\
|
||||
Format a value to the set number of decimals
|
||||
\*********************************************************************************************/
|
||||
|
||||
@@ -78,7 +78,7 @@ const __FlashStringHelper * getLabel(LabelType::Enum label) {
|
||||
|
||||
case LabelType::JSON_BOOL_QUOTES: return F("JSON bool output without quotes");
|
||||
case LabelType::ENABLE_TIMING_STATISTICS: return F("Collect Timing Statistics");
|
||||
|
||||
case LabelType::TASKVALUESET_ALL_PLUGINS: return F("Allow TaskValueSet on all plugins");
|
||||
|
||||
case LabelType::BOOT_TYPE: return F("Last Boot Cause");
|
||||
case LabelType::BOOT_COUNT: return F("Boot Count");
|
||||
@@ -249,6 +249,7 @@ String getValue(LabelType::Enum label) {
|
||||
|
||||
case LabelType::JSON_BOOL_QUOTES: return jsonBool(Settings.JSONBoolWithoutQuotes());
|
||||
case LabelType::ENABLE_TIMING_STATISTICS: return jsonBool(Settings.EnableTimingStats());
|
||||
case LabelType::TASKVALUESET_ALL_PLUGINS: return jsonBool(Settings.AllowTaskValueSetAllPlugins());
|
||||
|
||||
case LabelType::BOOT_TYPE: return getLastBootCauseString();
|
||||
case LabelType::BOOT_COUNT: break;
|
||||
|
||||
@@ -52,6 +52,7 @@ struct LabelType {
|
||||
|
||||
JSON_BOOL_QUOTES,
|
||||
ENABLE_TIMING_STATISTICS,
|
||||
TASKVALUESET_ALL_PLUGINS,
|
||||
|
||||
BOOT_TYPE, // Cold boot
|
||||
BOOT_COUNT, // 0
|
||||
|
||||
@@ -191,7 +191,7 @@ unsigned int P044_Task::CRC16(const String& buf, int len)
|
||||
Returns false on a datagram start ('/'), end ('!') or invalid character
|
||||
*/
|
||||
bool P044_Task::validP1char(char ch) {
|
||||
if (((ch >= '0') && (ch <= '9')) || ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')))
|
||||
if (isAlphaNumeric(ch))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ void handle_advanced() {
|
||||
Settings.UseLastWiFiFromRTC(isFormItemChecked(LabelType::WIFI_USE_LAST_CONN_FROM_RTC));
|
||||
Settings.JSONBoolWithoutQuotes(isFormItemChecked(LabelType::JSON_BOOL_QUOTES));
|
||||
Settings.EnableTimingStats(isFormItemChecked(LabelType::ENABLE_TIMING_STATISTICS));
|
||||
Settings.AllowTaskValueSetAllPlugins(isFormItemChecked(LabelType::TASKVALUESET_ALL_PLUGINS));
|
||||
#ifdef ESP8266
|
||||
Settings.UseAlternativeDeepSleep(isFormItemChecked(LabelType::DEEP_SLEEP_ALTERNATIVE_CALL));
|
||||
#endif
|
||||
@@ -211,6 +212,8 @@ void handle_advanced() {
|
||||
#ifdef USES_TIMING_STATS
|
||||
addFormCheckBox(LabelType::ENABLE_TIMING_STATISTICS, Settings.EnableTimingStats());
|
||||
#endif
|
||||
addFormCheckBox(LabelType::TASKVALUESET_ALL_PLUGINS, Settings.AllowTaskValueSetAllPlugins());
|
||||
|
||||
#ifdef ESP8266
|
||||
addFormCheckBox(LabelType::DEEP_SLEEP_ALTERNATIVE_CALL, Settings.UseAlternativeDeepSleep());
|
||||
#endif
|
||||
|
||||
@@ -131,6 +131,7 @@ void handle_config() {
|
||||
Settings.Name[25] = 0;
|
||||
SecuritySettings.Password[25] = 0;
|
||||
addFormTextBox(F("Unit Name"), F("name"), Settings.Name, 25);
|
||||
addFormNote(String(F("Hostname: ")) + NetworkCreateRFCCompliantHostname());
|
||||
addFormNumericBox(F("Unit Number"), F("unit"), Settings.Unit, 0, UNIT_NUMBER_MAX);
|
||||
addFormCheckBox(F("Append Unit Number to hostname"), F("appendunittohostname"), Settings.appendUnitToHostname());
|
||||
addFormPasswordBox(F("Admin Password"), F("password"), SecuritySettings.Password, 25);
|
||||
|
||||
Reference in New Issue
Block a user