Merge branch 'mega' of https://github.com/letscontrolit/ESPEasy into feature/p008-add-option-for-reversed-decoding

This commit is contained in:
Ton Huisman
2021-08-07 08:51:41 +02:00
27 changed files with 1576 additions and 1044 deletions
+89 -5
View File
@@ -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

+41 -26
View File
@@ -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

+28 -29
View File
@@ -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
.. -------------
+89
View File
@@ -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:: `.`
+3 -3
View File
@@ -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`
+15
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1 -1
View File
@@ -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");
}
+8
View File
@@ -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 {
+3
View File
@@ -137,6 +137,9 @@ class SettingsStruct_tmpl
bool UseNTP() const;
void UseNTP(bool value);
bool AllowTaskValueSetAllPlugins() const;
void AllowTaskValueSetAllPlugins(bool value);
void validate();
+38 -2
View File
@@ -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;
}
+1 -1
View File
@@ -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
+44 -4
View File
@@ -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;
+4
View File
@@ -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
\*********************************************************************************************/
+2 -1
View File
@@ -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;
+1
View File
@@ -52,6 +52,7 @@ struct LabelType {
JSON_BOOL_QUOTES,
ENABLE_TIMING_STATISTICS,
TASKVALUESET_ALL_PLUGINS,
BOOT_TYPE, // Cold boot
BOOT_COUNT, // 0
+1 -1
View File
@@ -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;
}
+3
View File
@@ -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
+1
View File
@@ -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);