Skip to content

Commit

Permalink
Merge pull request #4076 from tonhuisman/feature/P020-add-option-to-i…
Browse files Browse the repository at this point in the history
…gnore-networkclient

[P020] Add option to process events without network client connected
  • Loading branch information
TD-er committed Jun 14, 2022
2 parents c0e0a03 + fc02701 commit 1bd548a
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 44 deletions.
53 changes: 42 additions & 11 deletions src/_P020_Ser2Net.ino
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
// #################################### Plugin 020: Ser2Net ##############################################
// #######################################################################################################

/************
* Changelog:
* 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.
***************************************************************/

# include "src/Helpers/_Plugin_Helper_serial.h"
# include "src/PluginStructs/P020_data_struct.h"
Expand All @@ -27,6 +33,12 @@
# define P020_RESET_TARGET_PIN PCONFIG(6)
# define P020_RX_BUFFER PCONFIG(7)

# 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)


# define P020_QUERY_VALUE 0 // Temp placement holder until we know what selectors are needed.
# define P020_NR_OUTPUT_OPTIONS 1
Expand Down Expand Up @@ -105,19 +117,25 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
uint8_t serialConfChoice = serialHelper_convertOldSerialConfig(P020_SERIAL_CONFIG);
serialHelper_serialconfig_webformLoad(event, serialConfChoice);
{
uint8_t choice = P020_SERIAL_PROCESSING;
const __FlashStringHelper * options[3] = {
const __FlashStringHelper *options[3] = {
F("None"),
F("Generic"),
F("RFLink")
};
addFormSelector(F("Event processing"), F("p020_events"), 3, options, nullptr, choice);
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);
# 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(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

success = true;
break;
Expand All @@ -132,7 +150,11 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
P020_RX_WAIT = getFormItemInt(F("p020_rxwait"));
P020_RESET_TARGET_PIN = getFormItemInt(F("p020_resetpin"));
P020_RX_BUFFER = getFormItemInt(F("p020_rx_buffer"));
success = true;

bitWrite(P020_FLAGS, P020_FLAG_IGNORE_CLIENT, isFormItemChecked(F("p020_ignoreclient")));
bitWrite(P020_FLAGS, P020_FLAG_MULTI_LINE, isFormItemChecked(F("p020_multiline")));

success = true;
break;
}

Expand All @@ -159,6 +181,7 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
if (nullptr == task) {
break;
}
task->handleMultiLine = P020_HANDLE_MULTI_LINE;

// int rxPin =-1;
// int txPin =-1;
Expand All @@ -172,6 +195,9 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
CONFIG_PIN1 = rxPin;
CONFIG_PIN2 = txPin;
}

# ifndef LIMIT_BUILD_SIZE

if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("Ser2net: TaskIndex=");
log += event->TaskIndex;
Expand All @@ -189,6 +215,7 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
log += P020_SERIAL_PROCESSING;
addLogMove(LOG_LEVEL_INFO, log);
}
# endif // ifndef LIMIT_BUILD_SIZE

// serial0 on esp32 is Ser2net: port=2 rxPin=3 txPin=1; serial1 on esp32 is Ser2net: port=4 rxPin=13 txPin=15; Serial2 on esp32 is
// Ser2net: port=4 rxPin=16 txPin=17
Expand All @@ -202,15 +229,16 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
}

if (validGpio(P020_RESET_TARGET_PIN)) {
#ifndef BUILD_NO_DEBUG
# ifndef BUILD_NO_DEBUG

if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log;
log.reserve(38);
log += F("Ser2net : P020_RESET_TARGET_PIN : ");
log += P020_RESET_TARGET_PIN;
addLogMove(LOG_LEVEL_DEBUG, log);
}
#endif
# endif // ifndef BUILD_NO_DEBUG
pinMode(P020_RESET_TARGET_PIN, OUTPUT);
digitalWrite(P020_RESET_TARGET_PIN, LOW);
delay(500);
Expand All @@ -234,7 +262,7 @@ 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;
break;
}
task->checkServer();
success = true;
Expand All @@ -249,8 +277,12 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
break;
}

if (task->hasClientConnected()) {
task->handleClientIn(event);
bool hasClient = task->hasClientConnected();

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
}
success = true;
Expand All @@ -265,11 +297,10 @@ boolean Plugin_020(uint8_t function, struct EventStruct *event, String& string)
break;
}

if (task->hasClientConnected()) {
if (P020_IGNORE_CLIENT_CONNECTED || task->hasClientConnected()) {
task->handleSerialIn(event);
} else {
task->discardSerialIn();

}
success = true;
break;
Expand Down
103 changes: 74 additions & 29 deletions src/src/PluginStructs/P020_data_struct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,14 @@ void P020_Task::serialBegin(const ESPEasySerialPort port, int16_t rxPin, int16_t
ser2netSerial = new (std::nothrow) ESPeasySerial(port, rxPin, txPin);

if (nullptr != ser2netSerial) {
# if defined(ESP8266)
# if defined(ESP8266)
ser2netSerial->begin(baud, (SerialConfig)config);
# elif defined(ESP32)
# elif defined(ESP32)
ser2netSerial->begin(baud, config);
# endif // if defined(ESP8266)
# endif // if defined(ESP8266)
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("Ser2net : Serial opened"));
# endif // ifndef BUILD_NO_DEBUG
}
}
}
Expand All @@ -135,7 +137,9 @@ void P020_Task::serialEnd() {
delete ser2netSerial;
clearBuffer();
ser2netSerial = nullptr;
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("Ser2net : Serial closed"));
# endif // ifndef BUILD_NO_DEBUG
}
}

Expand Down Expand Up @@ -164,7 +168,9 @@ void P020_Task::handleSerialIn(struct EventStruct *event) {
do {
if (ser2netSerial->available()) {
if (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."));
# endif // ifndef BUILD_NO_DEBUG
ser2netSerial->read();
}
else { serial_buffer += (char)ser2netSerial->read(); }
Expand All @@ -177,11 +183,15 @@ void P020_Task::handleSerialIn(struct EventStruct *event) {
} while (true);

if (serial_buffer.length() > 0) {
ser2netClient.print(serial_buffer);
if (ser2netClient.connected()) { // Only send out if a client is connected
ser2netClient.print(serial_buffer);
}
rulesEngine(serial_buffer);
ser2netClient.flush();
clearBuffer();
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, F("Ser2Net : data send!"));
# endif // ifndef BUILD_NO_DEBUG
} // done
}

Expand All @@ -194,37 +204,72 @@ void P020_Task::discardSerialIn() {
}

// We can also use the rules engine for local control!
void P020_Task::rulesEngine(String message) {
if (!(Settings.UseRules)) { return; }
int NewLinePos = message.indexOf(F("\r\n"));

if (NewLinePos > 0) { message = message.substring(0, NewLinePos); }
String eventString;

switch (serial_processing) {
case 0: { break; }
case 1: { // Generic
eventString = F("!Serial#");
eventString += message;
break;
void P020_Task::rulesEngine(const String& message) {
if (!Settings.UseRules || message.isEmpty()) { return; }
int NewLinePos = 0;
uint16_t StartPos = 0;

NewLinePos = message.indexOf('\n', StartPos);

do {
if (NewLinePos < 0) {
NewLinePos = message.length();
}

String eventString;

if ((NewLinePos - StartPos) + 10 > 12) {
eventString.reserve((NewLinePos - StartPos) + 10); // Include the prefix
}
case 2: { // RFLink
message = message.substring(6); // RFLink, strip 20;xx; from incoming message

if (message.startsWith("ESPEASY")) // Special treatment for gpio values, strip unneeded parts...
{
message = message.substring(8); // Strip "ESPEASY;"
eventString = F("RFLink#");
// Remove preceeding CR also
if ((message[NewLinePos] == '\n') && (message[NewLinePos - 1] == '\r')) {
NewLinePos--;
}

switch (serial_processing) {
case 0: { break; }
case 1: { // Generic
if (NewLinePos > StartPos) {
eventString = F("!Serial#");
eventString += message.substring(StartPos, NewLinePos);
}
break;
}
else {
eventString = F("!RFLink#"); // default event as it comes in, literal match needed in rules, using '!'
case 2: { // RFLink
StartPos += 6; // RFLink, strip 20;xx; from incoming message

if (message.substring(StartPos, NewLinePos)
.startsWith(F("ESPEASY"))) { // Special treatment for gpio values, strip unneeded parts...
StartPos += 8; // Strip "ESPEASY;"
eventString = F("RFLink#");
} else {
eventString = F("!RFLink#"); // default event as it comes in, literal match needed in rules, using '!'
}

if (NewLinePos > StartPos) {
eventString += message.substring(StartPos, NewLinePos);
}
break;
}
eventString += message;
break;
} // switch

// Skip CR/LF
StartPos = NewLinePos; // Continue after what was already handled

while (StartPos < message.length() && (message[StartPos] == '\n' || message[StartPos] == '\r')) {
StartPos++;
}
} // switch

if (eventString.length() > 0) { eventQueue.addMove(std::move(eventString)); }
if (!eventString.isEmpty()) {
eventQueue.add(eventString);
}
NewLinePos = message.indexOf('\n', StartPos);

if (handleMultiLine && (NewLinePos < 0)) {
NewLinePos = message.length();
}
} while (handleMultiLine && NewLinePos > StartPos);
}

bool P020_Task::isInit() const {
Expand Down
9 changes: 5 additions & 4 deletions src/src/PluginStructs/P020_data_struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# include <ESPeasySerial.h>

# ifndef PLUGIN_020_DEBUG
# define PLUGIN_020_DEBUG false // extra logging in serial out
# define PLUGIN_020_DEBUG false // extra logging in serial out
# endif // ifndef PLUGIN_020_DEBUG

# define P020_STATUS_LED 12
Expand Down Expand Up @@ -42,7 +42,7 @@ struct P020_Task : public PluginTaskData_base {

void handleSerialIn(struct EventStruct *event);
void handleClientIn(struct EventStruct *event);
void rulesEngine(String message);
void rulesEngine(const String& message);

void discardSerialIn();

Expand All @@ -58,8 +58,9 @@ struct P020_Task : public PluginTaskData_base {
String net_buffer;
int checkI = 0;
ESPeasySerial *ser2netSerial = nullptr;
uint8_t serial_processing = 0;
taskIndex_t _taskIndex = INVALID_TASK_INDEX;
uint8_t serial_processing = 0;
taskIndex_t _taskIndex = INVALID_TASK_INDEX;
bool handleMultiLine = false;
};

#endif // ifdef USES_P020
Expand Down

0 comments on commit 1bd548a

Please sign in to comment.