Merge branch 'letscontrolit:mega' into P164_gases-ens160

This commit is contained in:
flashmark
2023-12-29 17:25:06 +01:00
committed by GitHub
30 changed files with 1276 additions and 435 deletions
+97 -7
View File
@@ -26,23 +26,111 @@ Supported hardware
|P020_usedby|
Configuration
-------------
.. image:: P020_DeviceConfiguration.png
* **Name** In the Name field a unique name should be entered.
* **Enabled** When unchecked the plugin is not enabled.
Sensor
^^^^^^
See: :ref:`SerialHelper_page`
Device Settings
^^^^^^^^^^^^^^^
**TODO**: Complete this documentation...
* **TCP Port**: The port for an external network client to read the data from, range 1..65535. The used port number must be unique within the device.
.. Commands available
.. ^^^^^^^^^^^^^^^^^^
* **Baud Rate / Serial config**: See *Serial helper configuration*, above.
.. .. include:: P020_commands.repl
* **Event Processing**: Select the type of data that is expected, to enable correct preprocessing. Available options:
.. Events
.. ~~~~~~
.. image:: P020_EventProcessingOptions.png
.. .. include:: P020_events.repl
* *None*: No special processing, what is received is sent out to the network client, not generating an event.
* *Generic*: No special processing, received data is sent to the network client, and an event ``!Serial#<message>``, containing the message as is, is generated. Spaces and newlines are processed as configured below.
* *RFLink*: Specifically designed for receiving serial data from RFLink devices, it follows this process:
* Remove the regular RFLink ``20;xx;`` prefix
* Check for prefix ``ESPEASY;``, if found, remove the prefix and generate event ``RFLink#<message>``. The ``<message>`` will contain commands to be handled by ESPEasy.
* If previous prefix is not found, generate event ``!RFLink#<message>``, containing the entire received data. Spaces and newlines are processed as configured below.
*Also see the* **Multiple lines processing** *option, below.*
* *P1 WiFi Gateway*: Process the data, received from a P1 Energy meter, that does a checksum validation, as included in the message. No separate data values are available in ESPEasy, these are usually handled by Home automation systems that support the P1 protocol via TCP network communication. An event ``<TaskName>#Data`` is generated when a valid P1 packet is received.
Replacing spaces or newlines should be **disabled** for the P1 protocol data to be handled properly as these replacements will disturb the checksum calculation, and also, the **Multiple lines processing** should be disabled if the data is to be handled as P1 protocol data, as that does contain newlines.
.. spacer
* **P1 #data event with message**: When enabled, the *P1 WiFi Gateway* Event Processing option will include the received message. **WARNING** This may easily cause memory overflow exceptions, especially when running on ESP8266 or other low-memory situations!
When selecting the **Event processing** options *Generic* or *RFLink*, after submitting the page will show extra options for the events generated:
.. image:: P020_EventOptions.png
* **Use Serial Port as eventname**: Instead of the default ``!Serial#<data>`` event, the name of the configured serial port will be used: (**Only** available for *Generic* Event processing)
.. spacer
* *(Unchecked)* -> ``Serial``
* *HW Serial0* -> ``serial0``
* *HW Serial0 swap* -> ``serial0``
* *HW Serial1* -> ``serial1``
* *HW Serial2* -> ``serial2``
* *SW Serial* -> ``serialsw``
* *I2C Serial* -> ``seriali2c``
* *USB HWCDC* -> ``serialhwcdc``
* *USB CDC* -> ``serialcdc``
.. spacer
* **Append Task Number to eventname**: Will append the task number to the event name, f.e. ``Serial8`` or ``RFLink12`` when task 8 or 12 is in use for this plugin. Can be combined with **Use Serial Port as eventname** if that is option is shown, resulting f.e. in ``serial0swap6`` etc. (Only available for *Generic* and *RFLink* Event processing)
.. spacer
* **Replace spaces in event by**: Here a single character can be selected to replace all spaces during receiving the data.
* **Replace newlines in event by**: Here a single character can be selected to replace all newlines during receiving the data. When enabled, all linefeeds are replaced, and all carriage returns (if any) are discarded.
.. image:: P020_ReplaceCharInEventOptions.png
The available set of replacement characters is ``, ; : . ! ^ | / \`` (comma, semicolon, colon, period, exclamation, caret, pipe, slash and backslash). When set to None, no replacement will be done.
* **Process events without client**: By default, if no network client is connected, no serial data will be received and processed either. Enabling this option enables receiving data and generating events without a TCP client connected.
* **Multiple lines processing**: When enabled, all received data will be split at a linefeed and sent out/event generated as separate messages.
* **RX Receive timeout (mSec)**: If parts of serial data packets are somewhat delayed, but should still be handled as a single message, then the delay to wait for the next part can be configured here. 0 disables the delay.
* **Reset target after init**: Select a GPIO pin that should be pulled low once during initialization of the plugin, used to synchronize the external serial data source with the plugin.
* **RX Buffer size (bytes)**: To not overburden the memory use of the plugin, the buffer size is set rather low. Some serial devices, like energy meters may require a larger buffer if the message exceeds this size. Range: 256..1024.
Led
^^^
* **Led enabled**: To enable a *data is being processed* activity led.
* **Led pin**: The GPIO pin the Led is connected to.
* **Led inverted**: Iverts the on/off state for the Led.
Data Acquisition
^^^^^^^^^^^^^^^^
The Data Acquisition and Send to Controller settings are standard available configuration items. Send to Controller only when one or more Controllers are configured. *Single event with all values* option is not applicable for this plugin.
Commands
~~~~~~~~
.. include:: P020_commands.repl
Change log
----------
@@ -50,6 +138,8 @@ Change log
.. versionchanged:: 2.0
...
|changed| 2022-12-13: Merge of P020 and P044 to reduce code size and combine features, as P044 was initially started as a spin-off from P020, but not evolved with the P020 features.
|added|
Major overhaul for 2.0 release.
Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

+37
View File
@@ -0,0 +1,37 @@
.. csv-table::
:header: "Command", "Extra information"
:widths: 20, 30
"
``serialsend,<content to send>``
``<content to send>``: Text that will be sent (nearly) unprocessed. Only the regular variable replacements will be applied before sending the content to the serial port.
","
Using this command, either from rules, via http or mqtt, the text that is provided as content is completely sent to the serial port. No extra data is added, other than any (system) variables that are included, being replaced.
"
"
``ser2netclientsend,<content to send>``
``<content to send>``: Text that will be sent (nearly) unprocessed. Only the regular variable replacements will be applied before sending the content to the network client.
","
This command will only send data to the network client, when there is an active connection.
Using this command, either from rules, via http or mqtt, the text that is provided as content is completely sent to the network client. No extra data is added, other than any (system) variables that are included, being replaced.
"
"
``serialsendmix,'<content to send>'[,...]``
``<content to send>``: Text and/or hex byte(s) (having 0x prefix) that will be sent (nearly) unprocessed. Only the regular variable replacements will be applied before sending the content to the serial port.
","
This command requires quotes to be used if spaces or commas are part of the content.
Any data can be sent, even if it can not be typed in a text content, by specifying that as a separate argument: ``serialsendmix,'text, optionally including spaces or commas',0xXX,'0xXXxx XX,xx-XX:xx'``
``'text, optionally including spaces or commas'``: Any text content to be sent to the serial port. Can contain variables. Quotes are only required if spaces or commas (separators) are used.
``0xXX``: A single character in hexadecimal notation (range: 0x00..0xFF), that is appended to the data to send.
``'0xXXxx XX,xx-XX:xx'``: A sequence of hexadecimal values (range: 0x00..0xFF), that *can* be separated by a space, comma, dash, colon, semicolon or period, or are just entered adjecent. Only the first 2 characters should be ``0x`` or ``0X``, the rest is interpreted as hex bytes, and appended to the string to send. Quotes are only required if space or comma separators are used.
Using this command, either from rules, via http or mqtt, the text that is provided as content is completely sent to the serial port. No extra data is added, other than any (system) variables that are included, being replaced.
"
+7 -1
View File
@@ -190,11 +190,17 @@ Option: Limit events being generated
* **Max. # events in event queue**: As a protection against event-overflow this configures a check for the queue-length, so if more than the selected number of events is still in the queue, new events will be discarded until some events are processed, and the remaining is less than this count. When set to 0 this check is disabled.
Option: Modify separater character in events
Option: Modify separator character in events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* **To replace by comma in event**: Select a character that is to be replaced by a comma, before it is put into the event-queue. There is a limited set of characters that can be replaced, to avoid ending up with malformed events.
Available options:
.. image:: P037_ReplaceByCommaOptions.png
The available set of replacement characters is ``! @ $ % ^ & * ; : . | / \`` (exclamation, at, dollar, percent, caret, ampersand, semicolon, colon, period, pipe, slash and backslash). When set to None, no replacement will be done.
This can be used to 'transform' the content of a JSON message so the used separator is a comma, for easier use in rules.
Topic Subscriptions
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

+32 -7
View File
@@ -26,23 +26,46 @@ Supported hardware
|P044_usedby|
.. note:: This plugin is now merged (back) into :ref:`P020_page` where it initially was forked off from, with using some predefined settings.
Configuration
-------------
.. image:: P044_DeviceConfiguration.png
* **Name** In the Name field a unique name should be entered.
* **Enabled** When unchecked the plugin is not enabled.
Sensor
^^^^^^
See: :ref:`SerialHelper_page`
Device Settings
^^^^^^^^^^^^^^^
**TODO**: Complete this documentation...
* **TCP Port**: The port for an external network client to read the data from, range 1..65535. The used port number must be unique within the device.
.. Commands available
.. ^^^^^^^^^^^^^^^^^^
* **Baud Rate / Serial config**: See *Serial helper configuration*, above.
.. .. include:: P044_commands.repl
* **P1 #data event with message**: When enabled, the *P1 WiFi Gateway* Event Processing option will include the received message. **WARNING** This may easily cause memory overflow exceptions, especially when running on ESP8266 or other low-memory situations!
.. Events
.. ~~~~~~
* **Process events without client**: By default, if no network client is connected, no serial data will be received and processed either. Enabling this option enables receiving data and generating events without a TCP client connected.
* **RX Receive timeout (mSec)**: If parts of serial data packets are somewhat delayed, but should still be handled as a single message, then the delay to wait for the next part can be configured here. 0 disables the delay.
* **Reset target after init**: Select a GPIO pin that should be pulled low once during initialization of the plugin, used to synchronize the external serial data source with the plugin.
Led
^^^
* **Led enabled**: To enable a *data is being processed* activity led.
* **Led pin**: The GPIO pin the Led is connected to.
* **Led inverted**: Iverts the on/off state for the Led.
.. .. include:: P044_events.repl
Change log
----------
@@ -50,6 +73,8 @@ Change log
.. versionchanged:: 2.0
...
|changed| 2022-10-08: Merge of P020 and P044 to reduce code size and combine features, as P044 was initially started as a spin-off from P020, but not evolved with the P020 features.
|added|
Major overhaul for 2.0 release.
Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

+3 -3
View File
@@ -249,10 +249,10 @@ P019 :ref:`P019_page`
.. include:: ../Plugin/P019_commands.repl
.. P020 :ref:`P020_page`
.. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
P020 :ref:`P020_page`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. .. include:: ../Plugin/P020_commands.repl
.. include:: ../Plugin/P020_commands.repl
P021 :ref:`P021_page`
+12 -11
View File
@@ -1,31 +1,32 @@
#include "ESPEasySerialPort.h"
const __FlashStringHelper* ESPEasySerialPort_toString(ESPEasySerialPort port)
const __FlashStringHelper* ESPEasySerialPort_toString(ESPEasySerialPort port, bool shortName)
{
switch (port) {
case ESPEasySerialPort::not_set: break;
#if USES_I2C_SC16IS752
case ESPEasySerialPort::sc16is752: return F("I2C Serial");
case ESPEasySerialPort::sc16is752: return shortName ? F("seriali2c") : F("I2C Serial");
#endif // if USES_I2C_SC16IS752
#ifdef ESP8266
case ESPEasySerialPort::serial0_swap: return F("HW Serial0 swap");
case ESPEasySerialPort::serial0_swap: return shortName ? F("serial0swap") : F("HW Serial0 swap");
#endif // ifdef ESP8266
case ESPEasySerialPort::serial0: return F("HW Serial0");
case ESPEasySerialPort::serial0: return shortName ? F("serial0") : F("HW Serial0");
#if SOC_UART_NUM > 1
case ESPEasySerialPort::serial1: return F("HW Serial1");
case ESPEasySerialPort::serial1: return shortName ? F("serial1") : F("HW Serial1");
#endif // if SOC_UART_NUM > 1
#if SOC_UART_NUM > 2
case ESPEasySerialPort::serial2: return F("HW Serial2");
case ESPEasySerialPort::serial2: return shortName ? F("serial2") : F("HW Serial2");
#endif // if SOC_UART_NUM > 2
#if USES_SW_SERIAL
case ESPEasySerialPort::software: return F("SW Serial");
case ESPEasySerialPort::software: return shortName ? F("serialsw") : F("SW Serial");
#endif // if USES_SW_SERIAL
#if USES_HWCDC
case ESPEasySerialPort::usb_hw_cdc: return F("USB HWCDC");
case ESPEasySerialPort::usb_hw_cdc: return shortName ? F("serialhwcdc") : F("USB HWCDC");
#endif // if USES_HWCDC
#if USES_USBCDC
case ESPEasySerialPort::usb_cdc_0: return F("USB CDC");
// case ESPEasySerialPort::usb_cdc_1: return F("USB CDC1");
case ESPEasySerialPort::usb_cdc_0: return shortName ? F("serialcdc") : F("USB CDC");
// case ESPEasySerialPort::usb_cdc_1: return F("USB CDC1");
#endif // if USES_USBCDC
case ESPEasySerialPort::MAX_SERIAL_TYPE: break;
@@ -103,7 +104,7 @@ bool validSerialPort(ESPEasySerialPort port)
#endif // if USES_HWCDC
#if USES_USBCDC
case ESPEasySerialPort::usb_cdc_0:
// case ESPEasySerialPort::usb_cdc_1:
// case ESPEasySerialPort::usb_cdc_1:
#endif // if USES_USBCDC
return true;
+1 -1
View File
@@ -36,7 +36,7 @@ enum class ESPEasySerialPort : uint8_t {
};
const __FlashStringHelper* ESPEasySerialPort_toString(ESPEasySerialPort port);
const __FlashStringHelper* ESPEasySerialPort_toString(ESPEasySerialPort port, bool shortName = false);
bool isHWserial(ESPEasySerialPort port);
+283 -120
View File
@@ -1,12 +1,28 @@
#include "_Plugin_Helper.h"
#ifdef USES_P020
#if defined(USES_P020) || defined(USES_P044)
// #######################################################################################################
// #################################### Plugin 020: Ser2Net ##############################################
// #################################### Plugin 044: P1WifiGateway ########################################
// #######################################################################################################
/************
* Changelog:
* 2023-08-26 tonhuisman: P044 mode: Set RX time-out default to 50 msec for better receive pace of P1 data
* 2023-08-17 tonhuisman: P1 data: Allow some extra reading timeout between the data and the checksum, as some meters need more time to
* calculate the CRC. Add CR/LF before sending P1 data.
* 2023-08-12 tonhuisman: Strip off occasional 8th bit from received data, to avoid unexpected failures on P1 data reception
* 2023-06-24 tonhuisman: Fix initialization with non-GPIO serial ports like CDC/HW-CDC
* Add option: append the task number to the event-name (Generic and RFLink event options)
* 2023-06-23 tonhuisman: Add option: use Serial Port name (serialxxx -> xxx= 0/1/2/0swap/i2c/sw/hwcdc/cdc) as event-name for Generic events
* 2023-06-02 tonhuisman: Allow buffer up to 2kB. Use ESPEasySerial buffering feature
* 2023-03-25 tonhuisman: Change serialsendmix to handle 0x00 also, by implementing parseHexTextData()
* 2022-12-12 tonhuisman: Add character conversion for the received serial data, act on Space and/or Newline
* 2022-10-11 tonhuisman: Add option for including the message in P1 #data event
* 2022-10-09 tonhuisman: Check P044 migration on PLUGIN_INIT too, still needs a manual save (from UI or by save command)
* 2022-10-08 tonhuisman: Merged code from P044 into this plugin, and use a global flag to emulate P044 with P020
* When USES_P044 is enabled, also USES_P020 will be enabled!
* Add Led settings, similar to P044
* 2022-05-28 tonhuisman: Add option to generate events for all lines of a multi-line message
* 2022-05-26 tonhuisman: Add option to allow processing without webclient connected.
* No older changelog available.
@@ -22,36 +38,45 @@
# define PLUGIN_NAME_020 "Communication - Serial Server"
# define PLUGIN_VALUENAME1_020 "Ser2Net"
# define PLUGIN_ID_020_044 44
# define PLUGIN_NAME_020_044 "Communication - P1 Wifi Gateway"
# define P020_SET_SERVER_PORT ExtraTaskSettings.TaskDevicePluginConfigLong[0]
# define P020_SET_BAUDRATE ExtraTaskSettings.TaskDevicePluginConfigLong[1]
bool P020_Emulate_P044 = false; // Global flag
# if defined(USES_P044) && !defined(USES_P044_ORG)
# define P020_GET_SERVER_PORT Cache.getTaskDevicePluginConfigLong(event->TaskIndex, 0)
# define P020_GET_BAUDRATE Cache.getTaskDevicePluginConfigLong(event->TaskIndex, 1)
// Emulate P044 using P020 with a global flag
boolean Plugin_044(uint8_t function, struct EventStruct *event, String& string) {
P020_Emulate_P044 = true;
// #define P020_SET_BAUDRATE ExtraTaskSettings.TaskDevicePluginConfigLong[1]
# define P020_RX_WAIT PCONFIG(4)
# define P020_SERIAL_CONFIG PCONFIG(1)
# define P020_SERIAL_PROCESSING PCONFIG(5)
# define P020_RESET_TARGET_PIN PCONFIG(6)
# define P020_RX_BUFFER PCONFIG(7)
boolean result = Plugin_020(function, event, string);
# define P020_FLAGS PCONFIG_LONG(0)
# define P020_FLAG_IGNORE_CLIENT 0
# define P020_FLAG_MULTI_LINE 1
# define P020_IGNORE_CLIENT_CONNECTED bitRead(P020_FLAGS, P020_FLAG_IGNORE_CLIENT)
# define P020_HANDLE_MULTI_LINE bitRead(P020_FLAGS, P020_FLAG_MULTI_LINE)
P020_Emulate_P044 = false;
return result;
}
bool P020_ConvertP044Settings(struct EventStruct *event) {
if (P020_Emulate_P044 && !P020_GET_P044_MODE_SAVED) {
// Convert existing P044 settings to P020 settings
P020_RX_WAIT = PCONFIG(0); // No conflict
// P020_SERIAL_CONFIG = PCONFIG(1); // No need to convert
P020_RESET_TARGET_PIN = CONFIG_PIN1;
# define P020_QUERY_VALUE 0 // Temp placement holder until we know what selectors are needed.
# define P020_NR_OUTPUT_OPTIONS 1
# define P020_QUERY1_CONFIG_POS 3
// 'Conflicting' stuff, set defaults to: Serial0, RX=gpio-3 and TX=gpio-1
CONFIG_PORT = static_cast<int>(ESPEasySerialPort::serial0); // P044 Serial port
CONFIG_PIN1 = 3; // P044 RX pin
CONFIG_PIN2 = 1; // P044 TX pin
# define P020_DEFAULT_SERVER_PORT 1234
# define P020_DEFAULT_BAUDRATE 115200
# define P020_DEFAULT_RESET_TARGET_PIN -1
# define P020_DEFAULT_RX_BUFFER 256
// Former P044 defaults
P020_FLAGS = 0u; // Reset
bitSet(P020_FLAGS, P020_FLAG_LED_ENABLED); // Led enabled...
P020_LED_PIN = P020_STATUS_LED; // ...and connected to GPIO-12
P020_SERIAL_PROCESSING = static_cast<int>(P020_Events::P1WiFiGateway); // Enable P1 WiFi Gateway processing
return true;
}
return false;
}
# endif // if defined(USES_P044) && !defined(USES_P044_ORG)
boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
{
@@ -61,7 +86,13 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_020;
if (P020_Emulate_P044) {
Device[++deviceCount].Number = PLUGIN_ID_020_044;
Device[deviceCount].SendDataOption = false;
} else {
Device[++deviceCount].Number = PLUGIN_ID_020;
Device[deviceCount].SendDataOption = true;
}
Device[deviceCount].Type = DEVICE_TYPE_SERIAL;
Device[deviceCount].VType = Sensor_VType::SENSOR_TYPE_STRING;
Device[deviceCount].Ports = 0;
@@ -69,25 +100,42 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
Device[deviceCount].InverseLogicOption = false;
Device[deviceCount].FormulaOption = false;
Device[deviceCount].ValueCount = 0;
Device[deviceCount].SendDataOption = true;
Device[deviceCount].TimerOption = false;
Device[deviceCount].GlobalSyncOption = false;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_020);
string = P020_Emulate_P044 ? F(PLUGIN_NAME_020_044) : F(PLUGIN_NAME_020);
break;
}
case PLUGIN_SET_DEFAULTS:
{
P020_SET_BAUDRATE = P020_DEFAULT_BAUDRATE;
P020_SET_SERVER_PORT = P020_DEFAULT_SERVER_PORT;
P020_RESET_TARGET_PIN = P020_DEFAULT_RESET_TARGET_PIN;
P020_RX_BUFFER = P020_DEFAULT_RX_BUFFER;
success = true;
if (P020_Emulate_P044) {
CONFIG_PORT = static_cast<int>(ESPEasySerialPort::serial0); // P044 Serial port
CONFIG_PIN1 = 3; // P044 RX pin
CONFIG_PIN2 = 1; // P044 TX pin
P020_SET_BAUDRATE = P020_DEFAULT_P044_BAUDRATE;
P020_SET_SERVER_PORT = P020_DEFAULT_P044_SERVER_PORT;
P020_RESET_TARGET_PIN = P020_DEFAULT_RESET_TARGET_PIN;
P020_SERIAL_PROCESSING = static_cast<int>(P020_Events::P1WiFiGateway); // Enable P1 WiFi Gateway processing (only)
P020_LED_PIN = P020_STATUS_LED;
P020_RX_WAIT = 50; // 50 msec for proper P1 packet receive mode
P020_REPLACE_SPACE = 0; // Force empty
P020_REPLACE_NEWLINE = 0;
P020_FLAGS = 0u; // Reset
bitSet(P020_FLAGS, P020_FLAG_LED_ENABLED);
bitSet(P020_FLAGS, P020_FLAG_P044_MODE_SAVED); // Inital config, no conversion needed
} else {
P020_SET_BAUDRATE = P020_DEFAULT_BAUDRATE;
P020_SET_SERVER_PORT = P020_DEFAULT_SERVER_PORT;
P020_RESET_TARGET_PIN = P020_DEFAULT_RESET_TARGET_PIN;
P020_RX_BUFFER = P020_DEFAULT_RX_BUFFER;
P020_LED_PIN = -1;
}
success = true;
break;
}
@@ -109,36 +157,111 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
{
string = F("RST: ");
string += formatGpioLabel(P020_RESET_TARGET_PIN, false);
string += event->String1;
string += F("LED: ");
string += formatGpioLabel(P020_GET_LED_ENABLED ? P020_LED_PIN : -1, false);
if ((P020_GET_LED_INVERTED == 1) && (P020_GET_LED_ENABLED)) {
string += F(" (inv)");
}
success = true;
break;
}
# ifdef USES_P044
case PLUGIN_WEBFORM_PRE_SERIAL_PARAMS:
{
// P044 Settings to convert?
if (P020_Emulate_P044 && P020_ConvertP044Settings(event)) {
addFormNote(F("Settings migrated from previous plugin version."));
}
break;
}
# endif // ifdef USES_P044
case PLUGIN_WEBFORM_LOAD:
{
addFormNumericBox(F("TCP Port"), F("p020_port"), P020_GET_SERVER_PORT, 0);
addFormNumericBox(F("Baud Rate"), F("p020_baud"), P020_GET_BAUDRATE, 0);
addFormNumericBox(F("TCP Port"), F("pport"), P020_GET_SERVER_PORT, 0);
# ifndef LIMIT_BUILD_SIZE
addUnit(F("0..65535"));
# endif // ifndef LIMIT_BUILD_SIZE
addFormNumericBox(F("Baud Rate"), F("pbaud"), P020_GET_BAUDRATE, 0);
uint8_t serialConfChoice = serialHelper_convertOldSerialConfig(P020_SERIAL_CONFIG);
serialHelper_serialconfig_webformLoad(event, serialConfChoice);
{
const __FlashStringHelper *options[3] = {
F("None"),
F("Generic"),
F("RFLink")
};
addFormSelector(F("Event processing"), F("p020_events"), 3, options, nullptr, P020_SERIAL_PROCESSING);
addFormCheckBox(F("Process events without client"), F("p020_ignoreclient"), P020_IGNORE_CLIENT_CONNECTED);
if (!P020_Emulate_P044) {
const __FlashStringHelper *options[] = {
F("None"),
F("Generic"),
F("RFLink"),
F("P1 WiFi Gateway")
};
const int optionValues[] = {
static_cast<int>(P020_Events::None),
static_cast<int>(P020_Events::Generic),
static_cast<int>(P020_Events::RFLink),
static_cast<int>(P020_Events::P1WiFiGateway),
};
constexpr int optionCount = NR_ELEMENTS(optionValues);
addFormSelector(F("Event processing"), F("pevents"),
optionCount, options, optionValues,
P020_SERIAL_PROCESSING);
}
addFormCheckBox(F("P1 #data event with message"), F("pp1event"), P020_GET_P1_EVENT_DATA);
# ifndef LIMIT_BUILD_SIZE
addFormNote(F("When enabled, passes the entire message in the event. <B>Warning:</B> can cause memory overflow issues!"));
# endif // ifndef LIMIT_BUILD_SIZE
if (P020_Events::Generic == static_cast<P020_Events>(P020_SERIAL_PROCESSING)) {
addFormCheckBox(F("Use Serial Port as eventname"), F("pevtname"), P020_GET_EVENT_SERIAL_ID);
# ifndef LIMIT_BUILD_SIZE
addFormNote(F("(Event processing: Generic only!)"));
# endif // ifndef LIMIT_BUILD_SIZE
}
if (P020_Events::P1WiFiGateway != static_cast<P020_Events>(P020_SERIAL_PROCESSING)) {
addFormCheckBox(F("Append Task Number to eventname"), F("papptask"), P020_GET_APPEND_TASK_ID);
# ifndef LIMIT_BUILD_SIZE
addFormNote(F("(Event processing: Generic and RFLink only!)"));
# endif // ifndef LIMIT_BUILD_SIZE
}
if (!P020_Emulate_P044) { // Not appropriate for P1 WiFi Gateway
addFormSeparatorCharInput(F("Replace spaces in event by"), F("replspace"),
P020_REPLACE_SPACE, F(P020_REPLACE_CHAR_SET), F(""));
addFormSeparatorCharInput(F("Replace newlines in event by"), F("replcrlf"),
P020_REPLACE_NEWLINE, F(P020_REPLACE_CHAR_SET), F(""));
}
addFormCheckBox(F("Process events without client"), F("pignoreclient"), P020_IGNORE_CLIENT_CONNECTED);
# ifndef LIMIT_BUILD_SIZE
addFormNote(F("When enabled, will process serial data without a network client connected."));
# endif // ifndef LIMIT_BUILD_SIZE
addFormCheckBox(F("Multiple lines processing"), F("p020_multiline"), P020_HANDLE_MULTI_LINE);
}
addFormNumericBox(F("RX Receive Timeout (mSec)"), F("p020_rxwait"), P020_RX_WAIT, 0, 20);
addFormPinSelect(PinSelectPurpose::Generic, F("Reset target after init"), F("p020_resetpin"), P020_RESET_TARGET_PIN);
addFormNumericBox(F("RX buffer size (bytes)"), F("p020_rx_buffer"), P020_RX_BUFFER, 256, 1024);
# ifndef LIMIT_BUILD_SIZE
addFormNote(F("Standard RX buffer 256B; higher values could be unstable; energy meters could require 1024B"));
# endif // ifndef LIMIT_BUILD_SIZE
if (!P020_Emulate_P044) { // Not appropriate for P1 WiFi Gateway
addFormCheckBox(F("Multiple lines processing"), F("pmultiline"), P020_HANDLE_MULTI_LINE);
}
}
{
addFormNumericBox(F("RX Receive Timeout (mSec)"), F("prxwait"), P020_RX_WAIT, 0, 200);
addFormPinSelect(PinSelectPurpose::Generic_output, F("Reset target after init"), F("presetpin"), P020_RESET_TARGET_PIN);
if (!P020_Emulate_P044) {
addFormNumericBox(F("RX buffer size (bytes)"), F("prx_buffer"), P020_RX_BUFFER, 256, 2048);
# ifndef LIMIT_BUILD_SIZE
addFormNote(F("Standard RX buffer 256B; higher values could be unstable; energy meters could require 1024B"));
# endif // ifndef LIMIT_BUILD_SIZE
}
}
{ // Led settings
addFormSubHeader(F("Led"));
addFormCheckBox(F("Led enabled"), F("pled"), P020_GET_LED_ENABLED);
addFormPinSelect(PinSelectPurpose::Generic_output, F("Led pin"), F("pledpin"), P020_LED_PIN);
addFormCheckBox(F("Led inverted"), F("pledinv"), P020_GET_LED_INVERTED == 1);
}
success = true;
break;
@@ -146,16 +269,43 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
P020_SET_SERVER_PORT = getFormItemInt(F("p020_port"));
P020_SET_BAUDRATE = getFormItemInt(F("p020_baud"));
P020_SERIAL_CONFIG = serialHelper_serialconfig_webformSave();
P020_SERIAL_PROCESSING = getFormItemInt(F("p020_events"));
P020_RX_WAIT = getFormItemInt(F("p020_rxwait"));
P020_RESET_TARGET_PIN = getFormItemInt(F("p020_resetpin"));
P020_RX_BUFFER = getFormItemInt(F("p020_rx_buffer"));
P020_SET_SERVER_PORT = getFormItemInt(F("pport"));
P020_SET_BAUDRATE = getFormItemInt(F("pbaud"));
P020_SERIAL_CONFIG = serialHelper_serialconfig_webformSave();
P020_RX_WAIT = getFormItemInt(F("prxwait"));
P020_RESET_TARGET_PIN = getFormItemInt(F("presetpin"));
bitWrite(P020_FLAGS, P020_FLAG_IGNORE_CLIENT, isFormItemChecked(F("p020_ignoreclient")));
bitWrite(P020_FLAGS, P020_FLAG_MULTI_LINE, isFormItemChecked(F("p020_multiline")));
if (P020_Emulate_P044) {
P020_SERIAL_PROCESSING = static_cast<int>(P020_Events::P1WiFiGateway); // Force P1 WiFi Gateway processing
} else {
P020_SERIAL_PROCESSING = getFormItemInt(F("pevents"));
P020_RX_BUFFER = getFormItemInt(F("prx_buffer"));
P020_REPLACE_SPACE = getFormItemInt(F("replspace"));
P020_REPLACE_NEWLINE = getFormItemInt(F("replcrlf"));
}
P020_LED_PIN = getFormItemInt(F("pledpin"));
uint32_t lSettings = 0u;
bitWrite(lSettings, P020_FLAG_IGNORE_CLIENT, isFormItemChecked(F("pignoreclient")));
bitWrite(lSettings, P020_FLAG_LED_ENABLED, isFormItemChecked(F("pled")));
bitWrite(lSettings, P020_FLAG_LED_INVERTED, isFormItemChecked(F("pledinv")));
bitWrite(lSettings, P020_FLAG_P1_EVENT_DATA, isFormItemChecked(F("pp1event")));
if (P020_Events::Generic == static_cast<P020_Events>(P020_SERIAL_PROCESSING)) {
bitWrite(lSettings, P020_FLAG_EVENT_SERIAL_ID, isFormItemChecked(F("pevtname")));
}
if (P020_Events::P1WiFiGateway != static_cast<P020_Events>(P020_SERIAL_PROCESSING)) {
bitWrite(lSettings, P020_FLAG_APPEND_TASK_ID, isFormItemChecked(F("papptask")));
}
if (P020_Emulate_P044) {
bitSet(lSettings, P020_FLAG_P044_MODE_SAVED); // Set to P044 configuration done on every save
} else {
bitWrite(lSettings, P020_FLAG_MULTI_LINE, isFormItemChecked(F("pmultiline")));
}
P020_FLAGS = lSettings;
success = true;
break;
@@ -163,6 +313,20 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
case PLUGIN_INIT:
{
# ifdef USES_P044
// P044 Settings to convert?
if (P020_Emulate_P044 && P020_ConvertP044Settings(event)) {
addLog(LOG_LEVEL_INFO, F("P1 : Automatic settings conversion, please save settings manually."));
bitSet(P020_FLAGS, P020_FLAG_P044_MODE_SAVED); // Set to P044 configuration done on next save
}
# endif // ifdef USES_P044
if (P020_GET_LED_ENABLED && validGpio(P020_LED_PIN)) {
pinMode(P020_LED_PIN, OUTPUT);
digitalWrite(P020_LED_PIN, P020_GET_LED_INVERTED ? 1 : 0);
}
if ((P020_GET_SERVER_PORT == 0) || (P020_GET_BAUDRATE == 0)) {
clearPluginTaskData(event->TaskIndex);
break;
@@ -175,22 +339,19 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
// It was already created and initialzed
// So don't recreate to keep the webserver running.
} else {
initPluginTaskData(event->TaskIndex, new (std::nothrow) P020_Task(event->TaskIndex));
initPluginTaskData(event->TaskIndex, new (std::nothrow) P020_Task(event));
task = static_cast<P020_Task *>(getPluginTaskData(event->TaskIndex));
}
if (nullptr == task) {
break;
}
task->handleMultiLine = P020_HANDLE_MULTI_LINE;
task->handleMultiLine = P020_HANDLE_MULTI_LINE && static_cast<P020_Events>(P020_SERIAL_PROCESSING) != P020_Events::P1WiFiGateway;
// int rxPin =-1;
// int txPin =-1;
int rxPin = CONFIG_PIN1;
int txPin = CONFIG_PIN2;
const ESPEasySerialPort port = static_cast<ESPEasySerialPort>(CONFIG_PORT);
// const ESPEasySerialPort port= ESPEasySerialPort::serial0;
if ((rxPin < 0) && (txPin < 0)) {
ESPeasySerialType::getSerialTypePins(port, rxPin, txPin);
CONFIG_PIN1 = rxPin;
@@ -200,21 +361,14 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
# ifndef LIMIT_BUILD_SIZE
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("Ser2net: TaskIndex=");
log += event->TaskIndex;
log += F(" port=");
log += CONFIG_PORT;
log += F(" rxPin=");
log += rxPin;
log += F(" txPin=");
log += txPin;
log += F(" BAUDRATE=");
log += P020_GET_BAUDRATE;
log += F(" SERVER_PORT=");
log += P020_GET_SERVER_PORT;
log += F(" SERIAL_PROCESSING=");
log += P020_SERIAL_PROCESSING;
addLogMove(LOG_LEVEL_INFO, log);
addLog(LOG_LEVEL_INFO, strformat(F("Ser2Net: TaskIndex=%d port=%d rxPin=%d txPin=%d BAUDRATE=%d SERVER_PORT=%d SERIAL_PROCESSING=%d"),
event->TaskIndex + 1,
CONFIG_PORT,
rxPin,
txPin,
P020_GET_BAUDRATE,
P020_GET_SERVER_PORT,
P020_SERIAL_PROCESSING));
}
# endif // ifndef LIMIT_BUILD_SIZE
@@ -245,8 +399,24 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
pinMode(P020_RESET_TARGET_PIN, INPUT_PULLUP);
}
task->serial_processing = P020_SERIAL_PROCESSING;
success = true;
task->serial_processing = static_cast<P020_Events>(P020_SERIAL_PROCESSING);
task->_P1EventData = P020_GET_P1_EVENT_DATA;
task->blinkLED();
if (task->serial_processing == P020_Events::P1WiFiGateway) {
task->_CRCcheck = P020_GET_BAUDRATE == 115200;
# ifndef BUILD_NO_DEBUG
if (task->_CRCcheck) {
addLog(LOG_LEVEL_DEBUG, F("P1 : DSMR version 5 meter, CRC on"));
} else {
addLog(LOG_LEVEL_DEBUG, F("P1 : DSMR version 4 meter, CRC off"));
}
# endif // ifndef BUILD_NO_DEBUG
}
success = true;
break;
}
@@ -266,11 +436,10 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
{
P020_Task *task = static_cast<P020_Task *>(getPluginTaskData(event->TaskIndex));
if (nullptr == task) {
break;
if (nullptr != task) {
task->checkServer();
success = true;
}
task->checkServer();
success = true;
break;
}
@@ -278,19 +447,18 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
{
P020_Task *task = static_cast<P020_Task *>(getPluginTaskData(event->TaskIndex));
if (nullptr == task) {
break;
}
if (nullptr != task) {
bool hasClient = task->hasClientConnected();
bool hasClient = task->hasClientConnected();
if (P020_IGNORE_CLIENT_CONNECTED || hasClient) {
if (hasClient) {
task->handleClientIn(event);
if (P020_IGNORE_CLIENT_CONNECTED || hasClient) {
if (hasClient) {
task->handleClientIn(event);
}
task->handleSerialIn(event); // in case of second serial connected, PLUGIN_SERIAL_IN is not called anymore
}
task->handleSerialIn(event); // in case of second serial connected, PLUGIN_SERIAL_IN is not called anymore
task->checkBlinkLED();
success = true;
}
success = true;
break;
}
@@ -298,48 +466,43 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
{
P020_Task *task = static_cast<P020_Task *>(getPluginTaskData(event->TaskIndex));
if (nullptr == task) {
break;
if (nullptr != task) {
if (P020_IGNORE_CLIENT_CONNECTED || task->hasClientConnected()) {
task->handleSerialIn(event);
} else {
task->discardSerialIn();
}
success = true;
}
if (P020_IGNORE_CLIENT_CONNECTED || task->hasClientConnected()) {
task->handleSerialIn(event);
} else {
task->discardSerialIn();
}
success = true;
break;
}
case PLUGIN_WRITE:
{
String command = parseString(string, 1);
P020_Task *task = static_cast<P020_Task *>(getPluginTaskData(event->TaskIndex));
if (nullptr == task) {
break;
}
if (nullptr != task) {
String command = parseString(string, 1);
if (equals(command, F("serialsend"))) {
task->ser2netSerial->write(string.substring(11).c_str());
task->ser2netSerial->flush();
success = true;
} else if (equals(command, F("serialsendmix"))) {
std::vector<uint8_t> argument = parseHexTextData(string);
if (argument.size() > 0) {
if (equals(command, F("serialsend"))) {
task->ser2netSerial->write(string.substring(11).c_str());
task->ser2netSerial->flush();
success = true;
} else if (equals(command, F("serialsendmix"))) {
std::vector<uint8_t> argument = parseHexTextData(string);
task->ser2netSerial->write(&argument[0], argument.size());
task->ser2netSerial->flush();
success = true;
} else if ((equals(command, F("ser2netclientsend"))) && (task->hasClientConnected())) {
task->ser2netClient.print(string.substring(18));
task->ser2netClient.flush();
success = true;
}
success = true;
} else if ((equals(command, F("ser2netclientsend"))) && (task->hasClientConnected())) {
task->ser2netClient.print(string.substring(18));
task->ser2netClient.flush();
success = true;
break;
}
break;
}
}
return success;
}
#endif // USES_P020
#endif // if defined(USES_P020) || defined(USES_P044)
+5 -11
View File
@@ -13,6 +13,7 @@
/**
* 2023-06-17, tonhuisman: Replace Device[].FormulaOption by Device[].DecimalsOnly option, as no (successful) PLUGIN_READ is done
* 2023-03-06, tonhuisman: Fix PLUGIN_INIT behavior to now always return success = true
* 2022-12-13, tonhuisman: Implement separator character input selector
* 2022-11-14, tonhuisman: Add support for selecting JSON sub-attributes, using the . notation, like main.sub (1 level only)
* 2022-11-02, tonhuisman: Enable plugin to generate events initially, like the plugin did before the mapping, filtering and json parsing
* features were added
@@ -196,11 +197,8 @@ boolean Plugin_037(uint8_t function, struct EventStruct *event, String& string)
}
# if P037_REPLACE_BY_COMMA_SUPPORT
{
String character = F(" ");
character[0] = (P037_REPLACE_BY_COMMA == 0 ? 0x20 : static_cast<uint8_t>(P037_REPLACE_BY_COMMA));
addRowLabel(F("To replace by comma in event"));
addTextBox(F("preplch"), character, 1, false, false, F("[!@$%^ &*;:.|/\\]"), F("widenumber"));
addUnit(F("Single character only, limited to: <b>! @ $ % ^ & * ; : . | / \\</b> is replaced by: <b>,</b> "));
addFormSeparatorCharInput(F("To replace by comma in event"), F("preplch"),
P037_REPLACE_BY_COMMA, F(P037_REPLACE_CHAR_SET), F(""));
}
# endif // if P037_REPLACE_BY_COMMA_SUPPORT
@@ -253,13 +251,9 @@ boolean Plugin_037(uint8_t function, struct EventStruct *event, String& string)
P037_SEND_EVENTS = isFormItemChecked(F("p037_send_events")) ? 1 : 0;
P037_DEDUPLICATE_EVENTS = isFormItemChecked(F("pdedupe")) ? 1 : 0;
P037_QUEUEDEPTH_EVENTS = getFormItemInt(F("pquedepth"));
# if P037_REPLACE_BY_COMMA_SUPPORT
String character = webArg(F("preplch"));
P037_REPLACE_BY_COMMA = character[0];
if (P037_REPLACE_BY_COMMA == 0x20) { // Space -> 0
P037_REPLACE_BY_COMMA = 0x0;
}
# if P037_REPLACE_BY_COMMA_SUPPORT
P037_REPLACE_BY_COMMA = getFormItemInt(F("preplch"));
# endif // if P037_REPLACE_BY_COMMA_SUPPORT
success = P037_data->webform_save(
+187 -134
View File
@@ -1,6 +1,7 @@
#include "_Plugin_Helper.h"
#ifdef USES_P044
//#################################### Plugin 044: P1WifiGateway ########################################
#ifdef USES_P044_ORG
// #################################### Plugin 044: P1WifiGateway ########################################
//
// based on P020 Ser2Net, extended by Ronald Leenes romix/-at-/macuser.nl
//
@@ -8,28 +9,22 @@
// Wemos D1 mini (see http://wemos.cc) and
// P1 wifi gateway shield (see http://www.esp8266thingies.nl for print design and kits)
// See also http://domoticx.com/p1-poort-slimme-meter-hardware/
//#######################################################################################################
// #######################################################################################################
/** Changelog:
* 2022-10-08 tonhuisman: Disable plugin-code and merge all functionality into P020 as it was originally a modified copy of that plugin
* *** This code is deprecated ***
* 2022-10-01 tonhuisman: Add Led configuration options (Enabled, Pin, Inverted), changed device configuration
* 2022-10-01 tonhuisman: Format source using Uncrustify
*/
#include "src/Helpers/_Plugin_Helper_serial.h"
#include "src/PluginStructs/P044_data_struct.h"
#include <ESPeasySerial.h>
# include "src/Helpers/_Plugin_Helper_serial.h"
# include "src/PluginStructs/P044_data_struct.h"
# include <ESPeasySerial.h>
#define PLUGIN_044
#define PLUGIN_ID_044 44
#define PLUGIN_NAME_044 "Communication - P1 Wifi Gateway"
#define P044_SET_WIFI_SERVER_PORT ExtraTaskSettings.TaskDevicePluginConfigLong[0]
#define P044_SET_BAUDRATE ExtraTaskSettings.TaskDevicePluginConfigLong[1]
#define P044_GET_WIFI_SERVER_PORT Cache.getTaskDevicePluginConfigLong(event->TaskIndex, 0)
#define P044_GET_BAUDRATE Cache.getTaskDevicePluginConfigLong(event->TaskIndex, 1)
#define P044_RX_WAIT PCONFIG(0)
#define P044_SERIAL_CONFIG PCONFIG(1)
#define P044_RESET_TARGET_PIN CONFIG_PIN1
# define PLUGIN_044
# define PLUGIN_ID_044 44
# define PLUGIN_NAME_044 "Communication - P1 Wifi Gateway"
boolean Plugin_044(uint8_t function, struct EventStruct *event, String& string)
@@ -38,165 +33,223 @@ boolean Plugin_044(uint8_t function, struct EventStruct *event, String& string)
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_044;
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
Device[deviceCount].Custom = true;
Device[deviceCount].TimerOption = false;
break;
}
{
Device[++deviceCount].Number = PLUGIN_ID_044;
Device[deviceCount].Type = DEVICE_TYPE_CUSTOM2;
Device[deviceCount].Custom = true;
Device[deviceCount].TimerOption = false;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_044);
break;
{
string = F(PLUGIN_NAME_044);
break;
}
case PLUGIN_SET_DEFAULTS:
{
P044_LED_PIN = P044_STATUS_LED; // Former default
break;
}
case PLUGIN_WEBFORM_SHOW_GPIO_DESCR:
{
string = concat(F("RST: "), formatGpioLabel(P044_RESET_TARGET_PIN, false));
string += event->String1;
string += concat(F("LED: "), formatGpioLabel((P044_LED_ENABLED & 0x7f) == 0 ? P044_LED_PIN : -1, false));
if ((P044_LED_INVERTED == 1) && ((P044_LED_ENABLED & 0x7f) == 0)) {
string += F(" (inv)");
}
success = true;
break;
}
case PLUGIN_WEBFORM_LOAD:
{
addFormNumericBox(F("TCP Port"), F("p044_port"), P044_GET_WIFI_SERVER_PORT, 0);
addFormNumericBox(F("Baud Rate"), F("p044_baud"), P044_GET_BAUDRATE, 0);
{
# ifdef USES_P020
String msg;
msg.reserve(132);
msg += F("This plugin is deprecated and will be removed in a future release. Please use P020 - ");
msg += getPluginNameFromPluginID(20);
addFormNote(msg);
# endif // ifdef USES_P020
LoadTaskSettings(event->TaskIndex);
{ // Serial settings
addFormSubHeader(F("Serial"));
uint8_t serialConfChoice = serialHelper_convertOldSerialConfig(P044_SERIAL_CONFIG);
serialHelper_serialconfig_webformLoad(event, serialConfChoice);
// FIXME TD-er: Why isn't this using the normal pin selection functions?
addFormPinSelect(PinSelectPurpose::Generic, F("Reset target after boot"), F("taskdevicepin1"), P044_RESET_TARGET_PIN);
addFormNumericBox(F("RX Receive Timeout (mSec)"), F("p044_rxwait"), P044_RX_WAIT, 0);
success = true;
break;
addFormNumericBox(F("Baud Rate"), F("pbaud"), P044_GET_BAUDRATE, 0, 115200);
}
{ // Device settings
addFormSubHeader(F("Device"));
addFormNumericBox(F("TCP Port"), F("pport"), P044_GET_WIFI_SERVER_PORT, 0, 65535);
# ifndef LIMIT_BUILD_SIZE
addUnit(F("0..65535"));
# endif // ifndef LIMIT_BUILD_SIZE
// FIXME TD-er: Why isn't this using the normal pin selection functions?
addFormPinSelect(PinSelectPurpose::Generic, F("Reset target after boot"), F("taskdevicepin1"), P044_RESET_TARGET_PIN);
addFormNumericBox(F("RX Receive Timeout (mSec)"), F("prxwait"), P044_RX_WAIT, 0);
}
{ // Led settings
addFormSubHeader(F("Led"));
addFormCheckBox(F("Led enabled"), F("pled"), (P044_LED_ENABLED & 0x7f) == 0);
addFormPinSelect(PinSelectPurpose::Generic, F("Led pin"), F("taskdevicepin2"), P044_LED_PIN);
addFormCheckBox(F("Led inverted"), F("pledinv"), P044_LED_INVERTED == 1);
}
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
P044_SET_WIFI_SERVER_PORT = getFormItemInt(F("p044_port"));
P044_SET_BAUDRATE = getFormItemInt(F("p044_baud"));
P044_RX_WAIT = getFormItemInt(F("p044_rxwait"));
P044_SERIAL_CONFIG = serialHelper_serialconfig_webformSave();
{
P044_SET_WIFI_SERVER_PORT = getFormItemInt(F("pport"));
P044_SET_BAUDRATE = getFormItemInt(F("pbaud"));
P044_RX_WAIT = getFormItemInt(F("prxwait"));
P044_LED_ENABLED = 0x80 + (isFormItemChecked(F("pled")) ? 0 : 1); // Invert + set 8th bit to confirm new settings have been
// saved
P044_LED_INVERTED = isFormItemChecked(F("pledinv")) ? 1 : 0;
P044_SERIAL_CONFIG = serialHelper_serialconfig_webformSave();
success = true;
break;
}
success = true;
break;
}
case PLUGIN_INIT:
{
pinMode(P044_STATUS_LED, OUTPUT);
digitalWrite(P044_STATUS_LED, 0);
{
if (((P044_LED_ENABLED & 0x7f) == 1) && (P044_LED_PIN != -1)) {
pinMode(P044_LED_PIN, OUTPUT);
digitalWrite(P044_LED_PIN, P044_LED_INVERTED == 1 ? 1 : 0);
}
if ((P044_GET_WIFI_SERVER_PORT == 0) || (P044_GET_BAUDRATE == 0)) {
clearPluginTaskData(event->TaskIndex);
break;
}
LoadTaskSettings(event->TaskIndex);
// try to reuse to keep webserver running
P044_Task *task = static_cast<P044_Task *>(getPluginTaskData(event->TaskIndex));
if (nullptr != task && task->isInit()) {
// It was already created and initialzed
// So don't recreate to keep the webserver running.
} else {
initPluginTaskData(event->TaskIndex, new (std::nothrow) P044_Task());
task = static_cast<P044_Task *>(getPluginTaskData(event->TaskIndex));
}
if (nullptr == task) {
break;
}
int rxPin;
int txPin;
// FIXME TD-er: Must use proper pin settings and standard ESPEasySerial wrapper
ESPeasySerialType::getSerialTypePins(ESPEasySerialPort::serial0, rxPin, txPin);
uint8_t serialconfig = serialHelper_convertOldSerialConfig(P044_SERIAL_CONFIG);
task->serialBegin(ESPEasySerialPort::not_set, rxPin, txPin, P044_GET_BAUDRATE, serialconfig);
task->startServer(P044_GET_WIFI_SERVER_PORT);
if (!task->isInit()) {
clearPluginTaskData(event->TaskIndex);
break;
}
if (validGpio(P044_RESET_TARGET_PIN)) {
pinMode(P044_RESET_TARGET_PIN, OUTPUT);
digitalWrite(P044_RESET_TARGET_PIN, LOW);
delay(500);
digitalWrite(P044_RESET_TARGET_PIN, HIGH);
pinMode(P044_RESET_TARGET_PIN, INPUT_PULLUP);
}
task->blinkLED();
if (P044_GET_BAUDRATE == 115200) {
#ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : DSMR version 4 meter, CRC on"));
#endif
task->CRCcheck = true;
} else {
#ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : DSMR version 4 meter, CRC off"));
#endif
task->CRCcheck = false;
}
success = true;
if ((P044_GET_WIFI_SERVER_PORT == 0) || (P044_GET_BAUDRATE == 0)) {
clearPluginTaskData(event->TaskIndex);
break;
}
// try to reuse to keep webserver running
P044_Task *task = static_cast<P044_Task *>(getPluginTaskData(event->TaskIndex));
if ((nullptr != task) && task->isInit()) {
// It was already created and initialzed
// So don't recreate to keep the webserver running.
} else {
initPluginTaskData(event->TaskIndex, new (std::nothrow) P044_Task(event));
task = static_cast<P044_Task *>(getPluginTaskData(event->TaskIndex));
}
if (nullptr == task) {
break;
}
int rxPin;
int txPin;
// FIXME TD-er: Must use proper pin settings and standard ESPEasySerial wrapper
ESPeasySerialType::getSerialTypePins(ESPEasySerialPort::serial0, rxPin, txPin);
uint8_t serialconfig = serialHelper_convertOldSerialConfig(P044_SERIAL_CONFIG);
task->serialBegin(ESPEasySerialPort::not_set, rxPin, txPin, P044_GET_BAUDRATE, serialconfig);
task->startServer(P044_GET_WIFI_SERVER_PORT);
if (!task->isInit()) {
clearPluginTaskData(event->TaskIndex);
break;
}
if (validGpio(P044_RESET_TARGET_PIN)) {
pinMode(P044_RESET_TARGET_PIN, OUTPUT);
digitalWrite(P044_RESET_TARGET_PIN, LOW);
delay(500);
digitalWrite(P044_RESET_TARGET_PIN, HIGH);
pinMode(P044_RESET_TARGET_PIN, INPUT_PULLUP);
}
task->blinkLED();
if (P044_GET_BAUDRATE == 115200) {
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : DSMR version 5 meter, CRC on"));
# endif // ifndef BUILD_NO_DEBUG
task->CRCcheck = true;
} else {
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : DSMR version 4 meter, CRC off"));
# endif // ifndef BUILD_NO_DEBUG
task->CRCcheck = false;
}
success = true;
break;
}
case PLUGIN_EXIT:
{
P044_Task *task = static_cast<P044_Task *>(getPluginTaskData(event->TaskIndex));
{
P044_Task *task = static_cast<P044_Task *>(getPluginTaskData(event->TaskIndex));
if (nullptr != task) {
task->stopServer();
task->serialEnd();
}
success = true;
break;
if (nullptr != task) {
task->stopServer();
task->serialEnd();
}
success = true;
break;
}
case PLUGIN_ONCE_A_SECOND:
{
P044_Task *task = static_cast<P044_Task *>(getPluginTaskData(event->TaskIndex));
if (nullptr == task) {
break;
}
{
P044_Task *task = static_cast<P044_Task *>(getPluginTaskData(event->TaskIndex));
if (nullptr != task) {
task->checkServer();
success = true;
break;
}
break;
}
case PLUGIN_TEN_PER_SECOND:
{
P044_Task *task = static_cast<P044_Task *>(getPluginTaskData(event->TaskIndex));
if (nullptr == task) {
break;
}
{
P044_Task *task = static_cast<P044_Task *>(getPluginTaskData(event->TaskIndex));
if (nullptr != task) {
if (task->hasClientConnected()) {
task->discardClientIn();
}
task->checkBlinkLED();
success = true;
break;
}
break;
}
case PLUGIN_SERIAL_IN:
{
P044_Task *task = static_cast<P044_Task *>(getPluginTaskData(event->TaskIndex));
if (nullptr == task) {
break;
}
{
P044_Task *task = static_cast<P044_Task *>(getPluginTaskData(event->TaskIndex));
if (nullptr != task) {
if (task->hasClientConnected()) {
task->handleSerialIn(event);
} else {
task->discardSerialIn();
}
success = true;
break;
}
break;
}
}
return success;
}
#endif // USES_P044
#endif // USES_P044_ORG
+3
View File
@@ -2346,6 +2346,9 @@ To create/register a plugin, you have to :
/******************************************************************************\
* Libraries dependencies *****************************************************
\******************************************************************************/
#if defined(USES_P044) && !defined(USES_P020) // P020 is used to replace/emulate P044
#define USES_P020
#endif
#if defined(USES_P020) || defined(USES_P049) || defined(USES_P052) || defined(USES_P053) || defined(USES_P056) || defined(USES_P065) || defined(USES_P071) || defined(USES_P075) || defined(USES_P077) || defined(USES_P078) || defined(USES_P082) || defined(USES_P085) || defined(USES_P087) || defined(USES_P093)|| defined(USES_P094) || defined(USES_P102) || defined(USES_P105) || defined(USES_P108) || defined(USES_P144) || defined(USES_C018)
// At least one plugin uses serial.
#ifndef PLUGIN_USES_SERIAL
@@ -62,6 +62,7 @@ enum PluginFunctions_e {
PLUGIN_PRIORITY_INIT_ALL , // Pre-initialize all plugins that are set to PowerManager priority (not implemented in plugins)
PLUGIN_PRIORITY_INIT , // Pre-initialize a singe plugins that is set to PowerManager priority
PLUGIN_WEBFORM_LOAD_ALWAYS , // Loaded *after* PLUGIN_WEBFORM_LOAD, also shown for remote data-feed devices
PLUGIN_WEBFORM_PRE_SERIAL_PARAMS , // Before serial parameters, convert additional parameters like baudrate or specific serial config
PLUGIN_MAX_FUNCTION // Leave as last one.
};
+3 -1
View File
@@ -843,6 +843,7 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str)
case PLUGIN_WEBFORM_SHOW_VALUES:
case PLUGIN_WEBFORM_SHOW_CONFIG:
case PLUGIN_WEBFORM_SHOW_I2C_PARAMS:
case PLUGIN_WEBFORM_PRE_SERIAL_PARAMS:
case PLUGIN_WEBFORM_SHOW_SERIAL_PARAMS:
case PLUGIN_WEBFORM_SHOW_GPIO_DESCR:
#if FEATURE_PLUGIN_STATS
@@ -868,7 +869,8 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str)
Function == PLUGIN_WEBFORM_LOAD_ALWAYS ||
Function == PLUGIN_SET_DEFAULTS ||
Function == PLUGIN_INIT_VALUE_RANGES ||
Function == PLUGIN_WEBFORM_SHOW_SERIAL_PARAMS
Function == PLUGIN_WEBFORM_SHOW_SERIAL_PARAMS ||
Function == PLUGIN_WEBFORM_PRE_SERIAL_PARAMS
) {
LoadTaskSettings(event->TaskIndex);
}
+2 -2
View File
@@ -17,8 +17,8 @@
#include <ESPEasySerialType.h>
String serialHelper_getSerialTypeLabel(ESPEasySerialPort serType) {
return ESPEasySerialPort_toString(serType);
String serialHelper_getSerialTypeLabel(ESPEasySerialPort serType, bool shortName) {
return ESPEasySerialPort_toString(serType, shortName);
}
void serialHelper_log_GpioDescription(ESPEasySerialPort typeHint, int config_pin1, int config_pin2) {
+4 -3
View File
@@ -11,7 +11,8 @@
struct ESPeasySerialType;
String serialHelper_getSerialTypeLabel(ESPEasySerialPort serType);
String serialHelper_getSerialTypeLabel(ESPEasySerialPort serType,
bool shortName = false);
void serialHelper_log_GpioDescription(ESPEasySerialPort typeHint,
int config_pin1,
@@ -40,8 +41,8 @@ ESPEasySerialPort serialHelper_getSerialType(struct EventStruct *event);
String serialHelper_getSerialTypeLabel(struct EventStruct *event);
#ifndef DISABLE_SC16IS752_Serial
void serialHelper_addI2CuartSelectors(int address,
int channel);
void serialHelper_addI2CuartSelectors(int address,
int channel);
#endif // ifndef DISABLE_SC16IS752_Serial
void serialHelper_webformLoad(struct EventStruct *event);
+332 -47
View File
@@ -10,12 +10,19 @@
# include "../Helpers/ESPEasy_Storage.h"
# include "../Helpers/Misc.h"
# define P020_RX_WAIT PCONFIG(4)
# define P020_RX_BUFFER PCONFIG(7)
P020_Task::P020_Task(struct EventStruct *event) : _taskIndex(event->TaskIndex) {
clearBuffer();
P020_Task::P020_Task(taskIndex_t taskIndex) : _taskIndex(taskIndex) {
serial_buffer.reserve(P020_DATAGRAM_MAX_SIZE);
if (P020_GET_LED_ENABLED) {
_ledPin = P020_LED_PIN; // Default pin (12) is already initialized in P020_Task
}
_ledEnabled = P020_GET_LED_ENABLED == 1;
_ledInverted = P020_GET_LED_INVERTED == 1;
_space = static_cast<char>(P020_REPLACE_SPACE);
_newline = static_cast<char>(P020_REPLACE_NEWLINE);
_port = static_cast<ESPEasySerialPort>(CONFIG_PORT);
_serialId = P020_GET_EVENT_SERIAL_ID;
_appendTaskId = P020_GET_APPEND_TASK_ID;
}
P020_Task::~P020_Task() {
@@ -23,6 +30,7 @@ P020_Task::~P020_Task() {
delete ser2netServer;
ser2netServer = nullptr;
}
if (ser2netSerial != nullptr) {
delete ser2netSerial;
ser2netSerial = nullptr;
@@ -50,10 +58,9 @@ void P020_Task::startServer(uint16_t portnumber) {
ser2netServer->begin();
if (serverActive(ser2netServer)) {
addLog(LOG_LEVEL_INFO, String(F("Ser2Net : WiFi server started at port ")) + portnumber);
addLog(LOG_LEVEL_INFO, strformat(F("Ser2Net: WiFi server started at port %d"), portnumber));
} else {
addLog(LOG_LEVEL_ERROR, String(F("Ser2Net : WiFi server start failed at port ")) +
portnumber + String(F(", retrying...")));
addLog(LOG_LEVEL_ERROR, strformat(F("Ser2Net: WiFi server start FAILED at port %d, retrying..."), portnumber));
}
}
}
@@ -64,7 +71,7 @@ void P020_Task::checkServer() {
ser2netServer->begin();
if (serverActive(ser2netServer)) {
addLog(LOG_LEVEL_INFO, F("Ser2net : WiFi server started"));
addLog(LOG_LEVEL_INFO, F("Ser2Net: WiFi server started"));
}
}
}
@@ -74,7 +81,7 @@ void P020_Task::stopServer() {
if (ser2netClient) { ser2netClient.stop(); }
clientConnected = false;
ser2netServer->close();
addLog(LOG_LEVEL_INFO, F("Ser2net : WiFi server closed"));
addLog(LOG_LEVEL_INFO, F("Ser2Net: WiFi server closed"));
delete ser2netServer;
ser2netServer = nullptr;
}
@@ -84,20 +91,24 @@ bool P020_Task::hasClientConnected() {
if ((nullptr != ser2netServer) && ser2netServer->hasClient())
{
if (ser2netClient) { ser2netClient.stop(); }
#if ESP_IDF_VERSION_MAJOR >= 5
ser2netClient = ser2netServer->accept();
#else
ser2netClient = ser2netServer->available();
#endif
#ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS
# ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS
// See: https://github.com/espressif/arduino-esp32/pull/6676
ser2netClient.setTimeout((CONTROLLER_CLIENTTIMEOUT_DFLT + 500) / 1000); // in seconds!!!!
Client *pClient = &ser2netClient;
pClient->setTimeout(CONTROLLER_CLIENTTIMEOUT_DFLT);
#else // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS
ser2netClient.setTimeout(CONTROLLER_CLIENTTIMEOUT_DFLT); // in msec as it should be!
#endif // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS
# else // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS
ser2netClient.setTimeout(CONTROLLER_CLIENTTIMEOUT_DFLT); // in msec as it should be!
# endif // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS
sendConnectedEvent(true);
addLog(LOG_LEVEL_INFO, F("Ser2Net : Client connected!"));
addLog(LOG_LEVEL_INFO, F("Ser2Net: Client connected!"));
}
if (ser2netClient.connected())
@@ -110,7 +121,7 @@ bool P020_Task::hasClientConnected() {
{
clientConnected = false;
sendConnectedEvent(false);
addLog(LOG_LEVEL_INFO, F("Ser2net : Client disconnected!"));
addLog(LOG_LEVEL_INFO, F("Ser2Net: Client disconnected!"));
}
}
return clientConnected;
@@ -125,14 +136,17 @@ void P020_Task::discardClientIn() {
}
void P020_Task::clearBuffer() {
serial_buffer = String();
serial_buffer.reserve(P020_DATAGRAM_MAX_SIZE);
serial_buffer = String();
_maxDataGramSize = serial_processing == P020_Events::P1WiFiGateway
? P020_P1_DATAGRAM_MAX_SIZE
: P020_DATAGRAM_MAX_SIZE;
serial_buffer.reserve(_maxDataGramSize);
}
void P020_Task::serialBegin(const ESPEasySerialPort port, int16_t rxPin, int16_t txPin, unsigned long baud, uint8_t config) {
serialEnd();
if (rxPin >= 0) {
if (ESPEasySerialPort::not_set != port) {
ser2netSerial = new (std::nothrow) ESPeasySerial(port, rxPin, txPin);
if (nullptr != ser2netSerial) {
@@ -142,7 +156,7 @@ void P020_Task::serialBegin(const ESPEasySerialPort port, int16_t rxPin, int16_t
ser2netSerial->begin(baud, config);
# endif // if defined(ESP8266)
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("Ser2net : Serial opened"));
addLog(LOG_LEVEL_DEBUG, F("Ser2Net: Serial opened"));
# endif // ifndef BUILD_NO_DEBUG
}
}
@@ -154,18 +168,18 @@ void P020_Task::serialEnd() {
clearBuffer();
ser2netSerial = nullptr;
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("Ser2net : Serial closed"));
addLog(LOG_LEVEL_DEBUG, F("Ser2Net: Serial closed"));
# endif // ifndef BUILD_NO_DEBUG
}
}
void P020_Task::handleClientIn(struct EventStruct *event) {
int count = ser2netClient.available();
int bytes_read = 0;
uint8_t net_buf[P020_DATAGRAM_MAX_SIZE];
size_t count = ser2netClient.available();
size_t bytes_read = 0;
uint8_t net_buf[_maxDataGramSize];
if (count > 0) {
if (count > P020_DATAGRAM_MAX_SIZE) { count = P020_DATAGRAM_MAX_SIZE; }
if (count > _maxDataGramSize) { count = _maxDataGramSize; }
bytes_read = ser2netClient.read(net_buf, count);
ser2netSerial->write(net_buf, bytes_read);
ser2netSerial->flush(); // Waits for the transmission of outgoing serial data to
@@ -178,21 +192,55 @@ void P020_Task::handleClientIn(struct EventStruct *event) {
void P020_Task::handleSerialIn(struct EventStruct *event) {
if (nullptr == ser2netSerial) { return; }
int RXWait = P020_RX_WAIT;
int timeOut = RXWait;
int RXWait = P020_RX_WAIT;
int timeOut = RXWait;
int maxExtend = 5;
bool done = false;
char ch;
do {
if (ser2netSerial->available()) {
if (serial_buffer.length() > static_cast<size_t>(P020_RX_BUFFER)) {
if ((serial_processing != P020_Events::P1WiFiGateway) // P1 handling without this check
&& (serial_buffer.length() > static_cast<size_t>(P020_RX_BUFFER))) {
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("Ser2Net : Error: Buffer overflow, discarded input."));
addLog(LOG_LEVEL_DEBUG, F("Ser2Net: Error: Buffer overflow, discarded input."));
# endif // ifndef BUILD_NO_DEBUG
ser2netSerial->read();
}
else { serial_buffer += (char)ser2netSerial->read(); }
else {
if (_ledEnabled) {
digitalWrite(_ledPin, _ledInverted ? 0 : 1);
}
ch = static_cast<char>(ser2netSerial->read());
if (serial_processing == P020_Events::P1WiFiGateway) {
done = handleP1Char(ch);
} else {
addChar(ch);
}
if (_ledEnabled) {
digitalWrite(_ledPin, _ledInverted ? 1 : 0);
}
}
if (done) {
break;
}
timeOut = RXWait; // if serial received, reset timeout counter
} else {
if (timeOut <= 0) { break; }
if (timeOut <= 0) {
if ((RXWait > 0) && (serial_processing == P020_Events::P1WiFiGateway) &&
((_state == ParserState::READING) ||
(_state == ParserState::CHECKSUM)) &&
(maxExtend > 0)) {
timeOut = RXWait;
maxExtend--;
} else {
break;
}
}
delay(1);
--timeOut;
}
@@ -200,13 +248,19 @@ void P020_Task::handleSerialIn(struct EventStruct *event) {
if (serial_buffer.length() > 0) {
if (ser2netClient.connected()) { // Only send out if a client is connected
if ((serial_processing == P020_Events::P1WiFiGateway) && !serial_buffer.endsWith(F("\r\n"))) {
serial_buffer += F("\r\n");
}
ser2netClient.print(serial_buffer);
}
blinkLED();
rulesEngine(serial_buffer);
ser2netClient.flush();
clearBuffer();
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("Ser2Net : data send!"));
addLog(LOG_LEVEL_DEBUG, F("Ser2Net: data send!"));
# endif // ifndef BUILD_NO_DEBUG
} // done
}
@@ -221,52 +275,78 @@ void P020_Task::discardSerialIn() {
// We can also use the rules engine for local control!
void P020_Task::rulesEngine(const String& message) {
if (!Settings.UseRules || message.isEmpty()) { return; }
if (!Settings.UseRules || message.isEmpty() || (P020_Events::None == serial_processing)) { return; }
int NewLinePos = 0;
uint16_t StartPos = 0;
NewLinePos = message.indexOf('\n', StartPos);
NewLinePos = handleMultiLine ? message.indexOf('\n', StartPos) : message.length();
do {
if (NewLinePos < 0) {
NewLinePos = message.length();
}
String eventString;
// Remove preceeding CR also
if ((message[NewLinePos] == '\n') && (message[NewLinePos - 1] == '\r')) {
NewLinePos--;
}
switch (serial_processing) {
case 0: { break; }
case 1: { // Generic
case P020_Events::None: { break; }
case P020_Events::Generic: { // Generic
if (NewLinePos > StartPos) {
eventQueue.addMove(std::move(concat(
F("!Serial#"),
message.substring(StartPos, NewLinePos))));
eventString = '!'; // F("!Serial");
if (_serialId) {
eventString += ESPEasySerialPort_toString(_port, true);
} else {
eventString += F("Serial");
}
if (_appendTaskId) {
eventString += (_taskIndex + 1);
}
eventString += '#';
eventString += message.substring(StartPos, NewLinePos);
}
break;
}
case 2: { // RFLink
StartPos += 6; // RFLink, strip 20;xx; from incoming message
case P020_Events::RFLink: { // RFLink
StartPos += 6; // RFLink, strip 20;xx; from incoming message
String eventString;
if ((NewLinePos - StartPos) >= 8 &&
message.substring(StartPos, StartPos + 8)
if (((NewLinePos - StartPos) >= 8) &&
message.substring(StartPos, StartPos + 8)
.startsWith(F("ESPEASY"))) { // Special treatment for gpio values, strip unneeded parts...
StartPos += 8; // Strip "ESPEASY;"
eventString = F("RFLink#");
eventString = F("RFLink");
} else {
eventString = F("!RFLink#"); // default event as it comes in, literal match needed in rules, using '!'
eventString = F("!RFLink"); // default event as it comes in, literal match needed in rules, using '!'
}
if (_appendTaskId) {
eventString += (_taskIndex + 1);
}
eventString += '#';
if (NewLinePos > StartPos) {
eventString += message.substring(StartPos, NewLinePos);
}
eventQueue.addMove(std::move(eventString));
break;
}
case P020_Events::P1WiFiGateway: // P1 WiFi Gateway
eventString = getTaskDeviceName(_taskIndex);
eventString += F("#Data");
if (_P1EventData) {
eventString += '=';
eventString += message; // Include entire message, may cause memory overflow!
eventString.replace(F("\n"), F(",")); // Make it a single line, comma-separated, as much as possible
eventString.replace(F("\r"), F("")); // We don't need no st*n carriage returns :)
}
break;
} // switch
// Skip CR/LF
@@ -276,6 +356,9 @@ void P020_Task::rulesEngine(const String& message) {
StartPos++;
}
if (!eventString.isEmpty()) {
eventQueue.add(eventString);
}
NewLinePos = message.indexOf('\n', StartPos);
if (handleMultiLine && (NewLinePos < 0)) {
@@ -293,4 +376,206 @@ void P020_Task::sendConnectedEvent(bool connected)
eventQueue.add(_taskIndex, F("Client"), (connected ? 1 : 0));
}
void P020_Task::blinkLED() {
if (_ledEnabled) {
_blinkLEDStartTime = millis();
digitalWrite(_ledPin, _ledInverted ? 0 : 1);
}
}
void P020_Task::checkBlinkLED() {
if (_ledEnabled && (_blinkLEDStartTime > 0) && (timePassedSince(_blinkLEDStartTime) >= 500)) {
digitalWrite(_ledPin, _ledInverted ? 1 : 0);
_blinkLEDStartTime = 0;
}
}
void P020_Task::addChar(char ch) {
if ((ch == 0x20) && (_space > 0)) { ch = _space; }
if (_newline > 0) {
if (ch == '\n') { ch = _newline; }
if (ch == '\r') { return; } // Ignore CR if LF is replaced
}
serial_buffer += ch;
}
/* checkDatagram
checks whether the P020_CHECKSUM of the data received from P1 matches the P020_CHECKSUM
attached to the telegram
*/
bool P020_Task::checkDatagram() const {
int endChar = serial_buffer.length() - 1;
if (_CRCcheck) {
endChar -= P020_CHECKSUM_LENGTH;
}
if ((endChar < 0) || (serial_buffer[0] != P020_DATAGRAM_START_CHAR) ||
(serial_buffer[endChar] != P020_DATAGRAM_END_CHAR)) {
return false;
}
if (!_CRCcheck) {
return true;
}
const int checksumStartIndex = endChar + 1;
# if PLUGIN_020_DEBUG
for (unsigned int cnt = 0; cnt < serial_buffer.length(); ++cnt) {
serialPrint(serial_buffer.substring(cnt, 1));
}
# endif // if PLUGIN_020_DEBUG
// calculate the CRC and check if it equals the hexadecimal one attached to the datagram
unsigned int crc = CRC16(serial_buffer, checksumStartIndex);
return strtoul(serial_buffer.substring(checksumStartIndex).c_str(), nullptr, 16) == crc;
}
/*
CRC16
based on code written by Jan ten Hove
https://github.com/jantenhove/P1-Meter-ESP8266
*/
unsigned int P020_Task::CRC16(const String& buf, int len) {
unsigned int crc = 0;
for (int pos = 0; pos < len; pos++) {
crc ^= static_cast<const unsigned int>(buf[pos]); // XOR byte into least sig. byte of crc
for (int i = 8; i != 0; i--) { // Loop over each bit
if ((crc & 0x0001) != 0) { // If the LSB is set
crc >>= 1; // Shift right and XOR 0xA001
crc ^= 0xA001;
} else { // Else LSB is not set
crc >>= 1; // Just shift right
}
}
}
return crc;
}
/*
validP1char
Checks if the character is valid as part of the P1 datagram contents and/or checksum.
Returns false on a datagram start ('/'), end ('!') or invalid character
*/
bool P020_Task::validP1char(char ch) {
return
isAlphaNumeric(ch) ||
ch == '.' ||
ch == ' ' ||
ch == '\\' || // Single backslash, but escaped in C++
ch == '\r' ||
ch == '\n' ||
ch == '(' ||
ch == ')' ||
ch == '-' ||
ch == '*' ||
ch == ':' ||
ch == '_';
}
bool P020_Task::handleP1Char(char ch) {
if (serial_buffer.length() >= _maxDataGramSize - 2) { // room for cr/lf
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : Error: Buffer overflow, discarded input."));
# endif // ifndef BUILD_NO_DEBUG
_state = ParserState::WAITING; // reset
}
ch &= 0x7F; // Strip off occasional 8th bit for now
bool done = false;
bool invalid = false;
switch (_state) {
case ParserState::WAITING:
if (ch == P020_DATAGRAM_START_CHAR) {
clearBuffer();
addChar(ch);
_state = ParserState::READING;
} // else ignore data
break;
case ParserState::READING:
if (validP1char(ch)) {
addChar(ch);
} else if (ch == P020_DATAGRAM_END_CHAR) {
addChar(ch);
if (_CRCcheck) {
checkI = 0;
_state = ParserState::CHECKSUM;
} else {
done = true;
}
} else if (ch == P020_DATAGRAM_START_CHAR) {
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : Error: Start detected, discarded input."));
# endif // ifndef BUILD_NO_DEBUG
_state = ParserState::WAITING; // reset
return handleP1Char(ch);
} else {
addLog(LOG_LEVEL_ERROR, strformat(F("P1 : Receiving unknown: %d,'%c'"), ch, ch));
invalid = true;
}
break;
case ParserState::CHECKSUM:
if (validP1char(ch)) {
addChar(ch);
++checkI;
if (checkI == P020_CHECKSUM_LENGTH) {
done = true;
}
} else {
invalid = true;
}
break;
} // switch
if (invalid) {
// input is not a datagram char
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : Error: DATA corrupt, discarded input."));
# endif // ifndef BUILD_NO_DEBUG
# if PLUGIN_020_DEBUG
serialPrint(F("faulty char>"));
serialPrint(String(ch));
serialPrintln("<");
# endif // if PLUGIN_020_DEBUG
_state = ParserState::WAITING; // reset
}
if (done) {
done = checkDatagram();
if (done) {
// add the cr/lf pair to the datagram ahead of reading both
// from serial as the datagram has already been validated
addChar('\r');
addChar('\n');
} else if (_CRCcheck) {
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : Error: Invalid CRC, dropped data"));
# endif // ifndef BUILD_NO_DEBUG
} else {
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : Error: Invalid datagram, dropped data"));
# endif // ifndef BUILD_NO_DEBUG
}
_state = ParserState::WAITING; // prepare for next one
}
return done;
}
#endif // ifdef USES_P020
+113 -16
View File
@@ -8,48 +8,130 @@
# include <ESPeasySerial.h>
# ifndef PLUGIN_020_DEBUG
# define PLUGIN_020_DEBUG false // extra logging in serial out
# define PLUGIN_020_DEBUG false // when true: extra logging in serial out !?!?!
# endif // ifndef PLUGIN_020_DEBUG
# define P020_SET_SERVER_PORT ExtraTaskSettings.TaskDevicePluginConfigLong[0]
# define P020_SET_BAUDRATE ExtraTaskSettings.TaskDevicePluginConfigLong[1]
# define P020_GET_SERVER_PORT Cache.getTaskDevicePluginConfigLong(event->TaskIndex, 0)
# define P020_GET_BAUDRATE Cache.getTaskDevicePluginConfigLong(event->TaskIndex, 1)
# define P020_REPLACE_CHAR_SET ",;:.!^|/\\"
# define P020_LED_PIN PCONFIG(0)
# define P020_SERIAL_CONFIG PCONFIG(1)
# define P020_REPLACE_SPACE PCONFIG(2)
# define P020_REPLACE_NEWLINE PCONFIG(3)
# define P020_RX_WAIT PCONFIG(4)
# define P020_SERIAL_PROCESSING PCONFIG(5)
# define P020_RESET_TARGET_PIN PCONFIG(6)
# define P020_RX_BUFFER PCONFIG(7)
# define P020_FLAGS PCONFIG_ULONG(0)
# define P020_FLAG_IGNORE_CLIENT 0
# define P020_FLAG_MULTI_LINE 1
# define P020_FLAG_LED_ENABLED 2
# define P020_FLAG_LED_INVERTED 3
# define P020_FLAG_P1_EVENT_DATA 4
# define P020_FLAG_P044_MODE_SAVED 8
# define P020_FLAG_EVENT_SERIAL_ID 9
# define P020_FLAG_APPEND_TASK_ID 10
# define P020_IGNORE_CLIENT_CONNECTED bitRead(P020_FLAGS, P020_FLAG_IGNORE_CLIENT)
# define P020_HANDLE_MULTI_LINE bitRead(P020_FLAGS, P020_FLAG_MULTI_LINE)
# define P020_GET_LED_ENABLED bitRead(P020_FLAGS, P020_FLAG_LED_ENABLED)
# define P020_GET_LED_INVERTED bitRead(P020_FLAGS, P020_FLAG_LED_INVERTED)
# define P020_GET_P1_EVENT_DATA bitRead(P020_FLAGS, P020_FLAG_P1_EVENT_DATA)
# define P020_GET_P044_MODE_SAVED bitRead(P020_FLAGS, P020_FLAG_P044_MODE_SAVED)
# define P020_GET_EVENT_SERIAL_ID bitRead(P020_FLAGS, P020_FLAG_EVENT_SERIAL_ID)
# define P020_GET_APPEND_TASK_ID bitRead(P020_FLAGS, P020_FLAG_APPEND_TASK_ID)
# define P020_DEFAULT_SERVER_PORT 1234
# define P020_DEFAULT_BAUDRATE 115200
# define P020_DEFAULT_RESET_TARGET_PIN -1
# define P020_DEFAULT_RX_BUFFER 256
# define P020_STATUS_LED 12
# define P020_DATAGRAM_MAX_SIZE 256
# define P020_DEFAULT_P044_SERVER_PORT 0
# define P020_DEFAULT_P044_BAUDRATE 9600
# define P020_CHECKSUM_LENGTH 4
# define P020_DATAGRAM_START_CHAR '/'
# define P020_DATAGRAM_END_CHAR '!'
# define P020_P1_DATAGRAM_MAX_SIZE 2048u
enum class P020_Events : uint8_t {
None = 0u,
Generic = 1u,
RFLink = 2u,
P1WiFiGateway = 3u,
};
struct P020_Task : public PluginTaskData_base {
P020_Task(taskIndex_t taskIndex);
P020_Task() = delete;
virtual ~P020_Task();
enum class ParserState : uint8_t {
WAITING,
READING,
CHECKSUM
};
P020_Task(struct EventStruct *event);
~P020_Task();
inline static bool serverActive(WiFiServer *server);
void startServer(uint16_t portnumber);
void checkServer();
void stopServer();
bool hasClientConnected();
void discardClientIn();
void clearBuffer();
void serialBegin(const ESPEasySerialPort port,
int16_t rxPin,
int16_t txPin,
unsigned long baud,
uint8_t config);
void serialEnd();
void serialEnd();
void handleSerialIn(struct EventStruct *event);
void handleClientIn(struct EventStruct *event);
void discardSerialIn();
void rulesEngine(const String& message);
void handleSerialIn(struct EventStruct *event);
void handleClientIn(struct EventStruct *event);
void rulesEngine(const String& message);
bool isInit() const;
void discardSerialIn();
void sendConnectedEvent(bool connected);
bool isInit() const;
void blinkLED();
void checkBlinkLED();
void sendConnectedEvent(bool connected);
void addChar(char ch);
/* checkDatagram
checks whether the P020_CHECKSUM of the data received from P1 matches the P020_CHECKSUM
attached to the telegram
*/
bool checkDatagram() const;
/*
CRC16
based on code written by Jan ten Hove
https://github.com/jantenhove/P1-Meter-ESP8266
*/
static unsigned int CRC16(const String& buf,
int len);
/*
validP1char
Checks if the character is valid as part of the P1 datagram contents and/or checksum.
Returns false on a datagram start ('/'), end ('!') or invalid character
*/
static bool validP1char(char ch);
bool handleP1Char(char ch);
WiFiServer *ser2netServer = nullptr;
uint16_t gatewayPort = 0;
@@ -59,9 +141,24 @@ struct P020_Task : public PluginTaskData_base {
String net_buffer;
int checkI = 0;
ESPeasySerial *ser2netSerial = nullptr;
uint8_t serial_processing = 0;
P020_Events serial_processing = P020_Events::None;
taskIndex_t _taskIndex = INVALID_TASK_INDEX;
bool handleMultiLine = false;
unsigned long _blinkLEDStartTime = 0;
int8_t _ledPin = -1;
bool _ledInverted = false;
bool _ledEnabled = false;
bool _CRCcheck = false;
bool _P1EventData = false;
size_t _maxDataGramSize = P020_DATAGRAM_MAX_SIZE;
ParserState _state = ParserState::WAITING;
char _space = 0;
char _newline = 0;
bool _serialId = false;
bool _appendTaskId = false;
ESPEasySerialPort _port;
};
#endif // ifdef USES_P020
+4 -2
View File
@@ -94,9 +94,11 @@
# define P037_OPERAND_LIST F("=%")
# define P037_FILTER_COUNT 3
# define P037_FILTER_LIST F("=-:") // Length should at least match P037_FILTER_COUNT
# define P037_FILTER_LIST F("=-:") // Length should at least match P037_FILTER_COUNT
# define P037_VALUE_SEPARATOR '\x02' // Separator outside of the normal ascii character values
# define P037_VALUE_SEPARATOR '\x02' // Separator outside of the normal ascii character values
# define P037_REPLACE_CHAR_SET "!@$%^&*;:.|/\\" // Allowable set of characters to be replaced by a comma
// Data structure
struct P037_data_struct : public PluginTaskData_base
+81 -54
View File
@@ -1,17 +1,25 @@
#include "../PluginStructs/P044_data_struct.h"
#ifdef USES_P044
#ifdef USES_P044_ORG
#include "../ESPEasyCore/Serial.h"
#include "../ESPEasyCore/ESPEasyNetwork.h"
# include "../ESPEasyCore/Serial.h"
# include "../ESPEasyCore/ESPEasyNetwork.h"
#include "../Globals/EventQueue.h"
# include "../Globals/EventQueue.h"
#include "../Helpers/ESPEasy_Storage.h"
#include "../Helpers/Misc.h"
# include "../Helpers/ESPEasy_Storage.h"
# include "../Helpers/Misc.h"
#define P044_RX_WAIT PCONFIG(0)
P044_Task::P044_Task(struct EventStruct *event) {
clearBuffer();
if (P044_LED_ENABLED & 0x80) {
_ledPin = P044_LED_PIN; // Default pin (12) is already initialized in P044_Task
}
_ledEnabled = (P044_LED_ENABLED & 0x7f) == 0; // Inverted setting and strip off new-settings bit
_ledInverted = P044_LED_INVERTED == 1;
}
P044_Task::~P044_Task() {
if (P1GatewayServer != nullptr) {
@@ -25,11 +33,12 @@ P044_Task::~P044_Task() {
}
bool P044_Task::serverActive(WiFiServer *server) {
#if defined(ESP8266)
# if defined(ESP8266)
return nullptr != server && server->status() != CLOSED;
#elif defined(ESP32)
# endif // if defined(ESP8266)
# if defined(ESP32)
return nullptr != server && *server;
#endif // if defined(ESP8266)
# endif // if defined(ESP32)
}
void P044_Task::startServer(uint16_t portnumber) {
@@ -45,7 +54,9 @@ void P044_Task::startServer(uint16_t portnumber) {
P1GatewayServer->begin();
if (serverActive(P1GatewayServer)) {
# ifndef LIMIT_BUILD_SIZE
addLog(LOG_LEVEL_INFO, concat(F("P1 : WiFi server started at port "), static_cast<int>(portnumber)));
# endif // ifndef LIMIT_BUILD_SIZE
} else {
addLog(LOG_LEVEL_ERROR, concat(F("P1 : WiFi server start failed at port "), static_cast<int>(portnumber)) + F(", retrying..."));
}
@@ -58,7 +69,9 @@ void P044_Task::checkServer() {
P1GatewayServer->begin();
if (serverActive(P1GatewayServer)) {
# ifndef LIMIT_BUILD_SIZE
addLog(LOG_LEVEL_INFO, F("P1 : WiFi server started"));
# endif // ifndef LIMIT_BUILD_SIZE
}
}
}
@@ -68,7 +81,9 @@ void P044_Task::stopServer() {
if (P1GatewayClient) { P1GatewayClient.stop(); }
clientConnected = false;
P1GatewayServer->close();
# ifndef LIMIT_BUILD_SIZE
addLog(LOG_LEVEL_INFO, F("P1 : WiFi server closed"));
# endif // ifndef LIMIT_BUILD_SIZE
delete P1GatewayServer;
P1GatewayServer = nullptr;
}
@@ -80,17 +95,19 @@ bool P044_Task::hasClientConnected() {
if (P1GatewayClient) { P1GatewayClient.stop(); }
P1GatewayClient = P1GatewayServer->available();
#ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS
# ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS
// See: https://github.com/espressif/arduino-esp32/pull/6676
P1GatewayClient.setTimeout((CONTROLLER_CLIENTTIMEOUT_DFLT + 500) / 1000); // in seconds!!!!
Client *pClient = &P1GatewayClient;
pClient->setTimeout(CONTROLLER_CLIENTTIMEOUT_DFLT);
#else // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS
P1GatewayClient.setTimeout(CONTROLLER_CLIENTTIMEOUT_DFLT); // in msec as it should be!
#endif // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS
# else // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS
P1GatewayClient.setTimeout(CONTROLLER_CLIENTTIMEOUT_DFLT); // in msec as it should be!
# endif // ifdef MUSTFIX_CLIENT_TIMEOUT_IN_SECONDS
# ifndef LIMIT_BUILD_SIZE
addLog(LOG_LEVEL_INFO, F("P1 : Client connected!"));
# endif // ifndef LIMIT_BUILD_SIZE
}
if (P1GatewayClient.connected())
@@ -102,7 +119,9 @@ bool P044_Task::hasClientConnected() {
if (clientConnected) // there was a client connected before...
{
clientConnected = false;
# ifndef LIMIT_BUILD_SIZE
addLog(LOG_LEVEL_INFO, F("P1 : Client disconnected!"));
# endif // ifndef LIMIT_BUILD_SIZE
}
}
return clientConnected;
@@ -117,13 +136,15 @@ void P044_Task::discardClientIn() {
}
void P044_Task::blinkLED() {
blinkLEDStartTime = millis();
digitalWrite(P044_STATUS_LED, 1);
if (_ledEnabled) {
blinkLEDStartTime = millis();
digitalWrite(_ledPin, _ledInverted ? 0 : 1);
}
}
void P044_Task::checkBlinkLED() {
if ((blinkLEDStartTime > 0) && (timePassedSince(blinkLEDStartTime) >= 500)) {
digitalWrite(P044_STATUS_LED, 0);
if (_ledEnabled && (blinkLEDStartTime > 0) && (timePassedSince(blinkLEDStartTime) >= 500)) {
digitalWrite(_ledPin, _ledInverted ? 1 : 0);
blinkLEDStartTime = 0;
}
}
@@ -159,11 +180,12 @@ bool P044_Task::checkDatagram() const {
const int checksumStartIndex = endChar + 1;
#ifdef PLUGIN_044_DEBUG
for (unsigned int cnt = 0; cnt < serial_buffer.length(); ++cnt) {
serialPrint(serial_buffer.substring(cnt, 1));
}
#endif
# ifdef PLUGIN_044_DEBUG
for (unsigned int cnt = 0; cnt < serial_buffer.length(); ++cnt) {
serialPrint(serial_buffer.substring(cnt, 1));
}
# endif // ifdef PLUGIN_044_DEBUG
// calculate the CRC and check if it equals the hexadecimal one attached to the datagram
unsigned int crc = CRC16(serial_buffer, checksumStartIndex);
@@ -207,9 +229,9 @@ bool P044_Task::validP1char(char ch) {
isAlphaNumeric(ch) ||
ch == '.' ||
ch == ' ' ||
ch == '\\'|| // Single backslash, but escaped in C++
ch == '\r'||
ch == '\n'||
ch == '\\' || // Single backslash, but escaped in C++
ch == '\r' ||
ch == '\n' ||
ch == '(' ||
ch == ')' ||
ch == '-' ||
@@ -226,14 +248,14 @@ void P044_Task::serialBegin(const ESPEasySerialPort port, int16_t rxPin, int16_t
P1EasySerial = new (std::nothrow) ESPeasySerial(port, rxPin, txPin);
if (nullptr != P1EasySerial) {
#if defined(ESP8266)
# if defined(ESP8266)
P1EasySerial->begin(baud, (SerialConfig)config);
#elif defined(ESP32)
# elif defined(ESP32)
P1EasySerial->begin(baud, config);
#endif // if defined(ESP8266)
# ifndef BUILD_NO_DEBUG
# endif // if defined(ESP8266)
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : Serial opened"));
#endif
# endif // ifndef BUILD_NO_DEBUG
}
}
state = ParserState::WAITING;
@@ -243,9 +265,9 @@ void P044_Task::serialEnd() {
if (nullptr != P1EasySerial) {
delete P1EasySerial;
P1EasySerial = nullptr;
# ifndef BUILD_NO_DEBUG
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : Serial closed"));
#endif
# endif // ifndef BUILD_NO_DEBUG
}
}
@@ -257,9 +279,14 @@ void P044_Task::handleSerialIn(struct EventStruct *event) {
do {
if (P1EasySerial->available()) {
digitalWrite(P044_STATUS_LED, 1);
if (_ledEnabled) {
digitalWrite(_ledPin, _ledInverted ? 0 : 1);
}
done = handleChar(P1EasySerial->read());
digitalWrite(P044_STATUS_LED, 0);
if (_ledEnabled) {
digitalWrite(_ledPin, _ledInverted ? 1 : 0);
}
if (done) { break; }
timeOut = RXWait; // if serial received, reset timeout counter
@@ -273,9 +300,9 @@ void P044_Task::handleSerialIn(struct EventStruct *event) {
if (done) {
P1GatewayClient.print(serial_buffer);
P1GatewayClient.flush();
# ifndef BUILD_NO_DEBUG
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : data send!"));
#endif
# endif // ifndef BUILD_NO_DEBUG
blinkLED();
eventQueue.add(event->TaskIndex, F("Data"), EMPTY_STRING);
@@ -284,10 +311,10 @@ void P044_Task::handleSerialIn(struct EventStruct *event) {
bool P044_Task::handleChar(char ch) {
if (serial_buffer.length() >= P044_DATAGRAM_MAX_SIZE - 2) { // room for cr/lf
# ifndef BUILD_NO_DEBUG
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : Error: Buffer overflow, discarded input."));
#endif
state = ParserState::WAITING; // reset
# endif // ifndef BUILD_NO_DEBUG
state = ParserState::WAITING; // reset
}
bool done = false;
@@ -316,9 +343,9 @@ bool P044_Task::handleChar(char ch) {
done = true;
}
} else if (ch == P044_DATAGRAM_START_CHAR) {
# ifndef BUILD_NO_DEBUG
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : Error: Start detected, discarded input."));
#endif
# endif // ifndef BUILD_NO_DEBUG
state = ParserState::WAITING; // reset
return handleChar(ch);
} else {
@@ -342,15 +369,15 @@ bool P044_Task::handleChar(char ch) {
if (invalid) {
// input is not a datagram char
# ifndef BUILD_NO_DEBUG
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : Error: DATA corrupt, discarded input."));
#endif
# endif // ifndef BUILD_NO_DEBUG
#ifdef PLUGIN_044_DEBUG
serialPrint(F("faulty char>"));
serialPrint(String(ch));
serialPrintln("<");
#endif
# ifdef PLUGIN_044_DEBUG
serialPrint(F("faulty char>"));
serialPrint(String(ch));
serialPrintln("<");
# endif // ifdef PLUGIN_044_DEBUG
state = ParserState::WAITING; // reset
}
@@ -363,13 +390,13 @@ bool P044_Task::handleChar(char ch) {
addChar('\r');
addChar('\n');
} else if (CRCcheck) {
# ifndef BUILD_NO_DEBUG
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : Error: Invalid CRC, dropped data"));
#endif
# endif // ifndef BUILD_NO_DEBUG
} else {
# ifndef BUILD_NO_DEBUG
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("P1 : Error: Invalid datagram, dropped data"));
#endif
# endif // ifndef BUILD_NO_DEBUG
}
state = ParserState::WAITING; // prepare for next one
}
@@ -390,4 +417,4 @@ bool P044_Task::isInit() const {
return nullptr != P1GatewayServer && nullptr != P1EasySerial;
}
#endif
#endif // ifdef USES_P044
+30 -14
View File
@@ -3,17 +3,29 @@
#include "../../_Plugin_Helper.h"
#ifdef USES_P044
#ifdef USES_P044_ORG
#include <ESPeasySerial.h>
# include <ESPeasySerial.h>
// #define PLUGIN_044_DEBUG // extra logging in serial out
#define P044_STATUS_LED 12
#define P044_CHECKSUM_LENGTH 4
#define P044_DATAGRAM_START_CHAR '/'
#define P044_DATAGRAM_END_CHAR '!'
#define P044_DATAGRAM_MAX_SIZE 2048u
# define P044_SET_WIFI_SERVER_PORT ExtraTaskSettings.TaskDevicePluginConfigLong[0]
# define P044_SET_BAUDRATE ExtraTaskSettings.TaskDevicePluginConfigLong[1]
# define P044_GET_WIFI_SERVER_PORT Cache.getTaskDevicePluginConfigLong(event->TaskIndex, 0)
# define P044_GET_BAUDRATE Cache.getTaskDevicePluginConfigLong(event->TaskIndex, 1)
# define P044_RX_WAIT PCONFIG(0)
# define P044_SERIAL_CONFIG PCONFIG(1)
# define P044_RESET_TARGET_PIN CONFIG_PIN1
# define P044_LED_PIN CONFIG_PIN2
# define P044_LED_ENABLED PCONFIG(2)
# define P044_LED_INVERTED PCONFIG(3)
# define P044_STATUS_LED 12
# define P044_CHECKSUM_LENGTH 4
# define P044_DATAGRAM_START_CHAR '/'
# define P044_DATAGRAM_END_CHAR '!'
# define P044_DATAGRAM_MAX_SIZE 2048u
struct P044_Task : public PluginTaskData_base {
@@ -23,7 +35,7 @@ struct P044_Task : public PluginTaskData_base {
CHECKSUM
};
P044_Task() = default;
P044_Task(struct EventStruct *event);
virtual ~P044_Task();
@@ -70,10 +82,10 @@ struct P044_Task : public PluginTaskData_base {
static bool validP1char(char ch);
void serialBegin(const ESPEasySerialPort port,
int16_t rxPin,
int16_t txPin,
unsigned long baud,
uint8_t config);
int16_t rxPin,
int16_t txPin,
unsigned long baud,
uint8_t config);
void serialEnd();
@@ -96,7 +108,11 @@ struct P044_Task : public PluginTaskData_base {
ESPeasySerial *P1EasySerial = nullptr;
unsigned long blinkLEDStartTime = 0;
size_t maxMessageSize = P044_DATAGRAM_MAX_SIZE / 4;
int8_t _ledPin = P044_STATUS_LED; // Former default
bool _ledEnabled = true; // Former default
bool _ledInverted = false;
};
#endif
#endif
#endif // ifdef USES_P044_ORG
#endif // ifndef PLUGINSTRUCTS_P044_DATA_STRUCT_H
+4 -1
View File
@@ -1148,9 +1148,12 @@ void devicePage_show_serial_config(taskIndex_t taskIndex)
{
struct EventStruct TempEvent(taskIndex);
serialHelper_webformLoad(&TempEvent);
String webformLoadString;
PluginCall(PLUGIN_WEBFORM_PRE_SERIAL_PARAMS, &TempEvent, webformLoadString);
serialHelper_webformLoad(&TempEvent);
PluginCall(PLUGIN_WEBFORM_SHOW_SERIAL_PARAMS, &TempEvent, webformLoadString);
}
#endif
+26
View File
@@ -394,6 +394,32 @@ void addFormIPaccessControlSelect(const __FlashStringHelper * label, const __Fla
addIPaccessControlSelect(id, choice);
}
// ********************************************************************************
// a Separator character selector
// ********************************************************************************
void addFormSeparatorCharInput(const __FlashStringHelper *rowLabel,
const __FlashStringHelper *id,
int value,
const String & charset,
const __FlashStringHelper *additionalText) {
const int len = charset.length() + 1;
String charList[len];
int charOpts[len];
charList[0] = F("None");
charOpts[0] = 0;
for (uint16_t i = 0; i < charset.length(); i++) {
charList[i + 1] = charset[i];
charOpts[i + 1] = static_cast<int>(charset[i]);
}
addFormSelector(rowLabel, id, len, charList, charOpts, value);
if (!String(additionalText).isEmpty()) {
addUnit(additionalText);
}
}
// ********************************************************************************
// Add a selector form
// ********************************************************************************
+9
View File
@@ -247,6 +247,15 @@ void addFormIPaccessControlSelect(const __FlashStringHelper * label,
const __FlashStringHelper * id,
int choice);
// ********************************************************************************
// a Separator character selector
// ********************************************************************************
void addFormSeparatorCharInput(const __FlashStringHelper *rowLabel,
const __FlashStringHelper *id,
int value,
const String & charset,
const __FlashStringHelper *additionalText);
// ********************************************************************************
// Add a selector form
// ********************************************************************************