From 1959b81138a210c84e2e1296e86133fe2207d013 Mon Sep 17 00:00:00 2001 From: Grovkillen Date: Wed, 4 Mar 2020 08:32:04 +0100 Subject: [PATCH 01/40] [rules] commented out old upload html --- src/WebServer_Rules.ino | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/WebServer_Rules.ino b/src/WebServer_Rules.ino index aa130ab3c..09e1725c8 100644 --- a/src/WebServer_Rules.ino +++ b/src/WebServer_Rules.ino @@ -79,7 +79,7 @@ void handle_rules() { currentSet = rulesSet; } - addHtml(F("
")); + //addHtml(F("")); html_table_class_normal(); html_TR(); html_table_header(F("Rules")); @@ -101,16 +101,16 @@ void handle_rules() { Rule_showRuleTextArea(fileName); - addFormSeparator(2); + //addFormSeparator(2); html_TR_TD(); - addSubmitButton(); + //addSubmitButton(); addButton(fileName, F("Download to file")); html_end_table(); - html_end_form(); - html_add_script(F( - "function addRulesLength() { var r_len = document.getElementById('rules').value.length; document.getElementById('rules_len').setAttribute('value', r_len); };"), - true); + //html_end_form(); + // html_add_script(F( + // "function addRulesLength() { var r_len = document.getElementById('rules').value.length; document.getElementById('rules_len').setAttribute('value', r_len); };"), + // true); sendHeadandTail_stdtemplate(true); TXBuffer.endStream(); @@ -536,7 +536,7 @@ void Rule_showRuleTextArea(const String& fileName) { addHtml(F("")); - addHtml(F("")); + //addHtml(F("")); html_TR_TD(); { @@ -554,7 +554,7 @@ void Rule_showRuleTextArea(const String& fileName) { if (size > RULES_MAX_SIZE) { addHtml(F("Filesize exceeds web editor limit!")); } - addHtml(F("

")); + //addHtml(F("

")); } bool Rule_Download(const String& path) From 73911474886e83fb7a89e9539d4e462b052e7169 Mon Sep 17 00:00:00 2001 From: Grovkillen Date: Wed, 4 Mar 2020 09:02:41 +0100 Subject: [PATCH 02/40] [rules] forms uncommented (needed for rules set) --- src/WebServer_Rules.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WebServer_Rules.ino b/src/WebServer_Rules.ino index 09e1725c8..a60607c3e 100644 --- a/src/WebServer_Rules.ino +++ b/src/WebServer_Rules.ino @@ -79,7 +79,7 @@ void handle_rules() { currentSet = rulesSet; } - //addHtml(F("")); + addHtml(F("")); html_table_class_normal(); html_TR(); html_table_header(F("Rules")); @@ -107,7 +107,7 @@ void handle_rules() { //addSubmitButton(); addButton(fileName, F("Download to file")); html_end_table(); - //html_end_form(); + html_end_form(); // html_add_script(F( // "function addRulesLength() { var r_len = document.getElementById('rules').value.length; document.getElementById('rules_len').setAttribute('value', r_len); };"), // true); From 5c729f3cb7fdd678e42bfb77d55bf45c8063409e Mon Sep 17 00:00:00 2001 From: Grovkillen Date: Wed, 4 Mar 2020 09:07:59 +0100 Subject: [PATCH 03/40] [rules] removed the "onSubmit" event --- src/WebServer_Rules.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WebServer_Rules.ino b/src/WebServer_Rules.ino index a60607c3e..2f9a9f15b 100644 --- a/src/WebServer_Rules.ino +++ b/src/WebServer_Rules.ino @@ -79,7 +79,7 @@ void handle_rules() { currentSet = rulesSet; } - addHtml(F("")); + addHtml(F("")); html_table_class_normal(); html_TR(); html_table_header(F("Rules")); From dcb8968f8269b5942311843b66571614f2767acc Mon Sep 17 00:00:00 2001 From: Grovkillen Date: Wed, 4 Mar 2020 09:24:09 +0100 Subject: [PATCH 04/40] [rules] narrowed scope of form (to not trigger onChange if btn clicked) --- src/WebServer_Rules.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WebServer_Rules.ino b/src/WebServer_Rules.ino index 2f9a9f15b..2e98f7a88 100644 --- a/src/WebServer_Rules.ino +++ b/src/WebServer_Rules.ino @@ -79,7 +79,6 @@ void handle_rules() { currentSet = rulesSet; } - addHtml(F("")); html_table_class_normal(); html_TR(); html_table_header(F("Rules")); @@ -96,6 +95,7 @@ void handle_rules() { } html_TR_TD(); + addHtml(F("")); addSelector(F("set"), RULESETS_MAX, options, optionValues, NULL, choice, true); addHelpButton(F("Tutorial_Rules")); @@ -105,9 +105,9 @@ void handle_rules() { html_TR_TD(); //addSubmitButton(); + html_end_form(); addButton(fileName, F("Download to file")); html_end_table(); - html_end_form(); // html_add_script(F( // "function addRulesLength() { var r_len = document.getElementById('rules').value.length; document.getElementById('rules_len').setAttribute('value', r_len); };"), // true); From 6eed61090e226a9d314a9523f9c5460d2ed05b0f Mon Sep 17 00:00:00 2001 From: Grovkillen Date: Wed, 4 Mar 2020 14:50:32 +0100 Subject: [PATCH 05/40] [rules] file upload instead of form upload --- src/WebServer_Rules.ino | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/WebServer_Rules.ino b/src/WebServer_Rules.ino index 2e98f7a88..08e7f531c 100644 --- a/src/WebServer_Rules.ino +++ b/src/WebServer_Rules.ino @@ -106,6 +106,39 @@ void handle_rules() { html_TR_TD(); //addSubmitButton(); html_end_form(); + addHtml(F("")); + addHtml(F("
Saved!
")); + addHtml(F("")); addButton(fileName, F("Download to file")); html_end_table(); // html_add_script(F( From 3ac67d40275c8347b074dfd4642a70e04d49acce Mon Sep 17 00:00:00 2001 From: Grovkillen Date: Wed, 4 Mar 2020 14:54:35 +0100 Subject: [PATCH 06/40] [rules] removed commented code --- src/WebServer_Rules.ino | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/WebServer_Rules.ino b/src/WebServer_Rules.ino index 08e7f531c..3dbf11cc7 100644 --- a/src/WebServer_Rules.ino +++ b/src/WebServer_Rules.ino @@ -101,10 +101,7 @@ void handle_rules() { Rule_showRuleTextArea(fileName); - //addFormSeparator(2); - html_TR_TD(); - //addSubmitButton(); html_end_form(); addHtml(F("")); addHtml(F("
Saved!
")); @@ -141,9 +138,6 @@ void handle_rules() { addHtml(F("};")); addButton(fileName, F("Download to file")); html_end_table(); - // html_add_script(F( - // "function addRulesLength() { var r_len = document.getElementById('rules').value.length; document.getElementById('rules_len').setAttribute('value', r_len); };"), - // true); sendHeadandTail_stdtemplate(true); TXBuffer.endStream(); From 13d6e3c6ffdacda635ccf5bf4aab6394a41f18ae Mon Sep 17 00:00:00 2001 From: Grovkillen Date: Wed, 4 Mar 2020 15:08:52 +0100 Subject: [PATCH 07/40] [rules] size is updated when saved --- src/WebServer_Rules.ino | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/WebServer_Rules.ino b/src/WebServer_Rules.ino index 3dbf11cc7..21af1e7b5 100644 --- a/src/WebServer_Rules.ino +++ b/src/WebServer_Rules.ino @@ -108,6 +108,7 @@ void handle_rules() { addHtml(F("")); + + html_add_script(true); + TXBuffer += jsSaveRules; + html_add_script_end(); + addButton(fileName, F("Download to file")); html_end_table(); sendHeadandTail_stdtemplate(true); diff --git a/src/src/Static/WebStaticData.h b/src/src/Static/WebStaticData.h index af3ebc789..4117c97e5 100644 --- a/src/src/Static/WebStaticData.h +++ b/src/src/Static/WebStaticData.h @@ -115,6 +115,19 @@ static const char jsClipboardCopyPart3[] PROGMEM = { "" }; + +static const char jsSaveRules[] PROGMEM = { + "function saveRulesFile(){document.getElementById(\"save_button\");" + "let e=document.getElementById(\"size\"),t=document.getElementById(\"rules\").value;" + "t=t.replace(/\\r?\\n/g,\"\\r\\n\");" + "let n=document.getElementById(\"set\").value,l=new File([t],\"rules\"+n+\".txt\",{type:\"text/plain\"}),a=new FormData;" + "a.append(\"file\",l),a.append(\"enctype\",\"multipart/form-data\");" + "let o=\"/rules\"+n+\".txt?callback=\"+Date.now();" + "fetch(o).then(e=>e.text()).then(l=>{if(t===l)console.log(\"nothing to save...\");" + "else{fetch(\"/upload\",{method:\"POST\",body:a}).then(e=>e.text()).then(l=>{let a=\"/rules\"+n+\".txt?callback=\"+Date.now();" + "fetch(a).then(e=>e.text()).then(n=>{t===n?(toasting(),e.innerHTML=t.length):console.log(\"error when saving...\")})})}})}" +}; + static const char DATA_UPDATE_SENSOR_VALUES_DEVICE_PAGE_JS[] PROGMEM = {0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x20,0x6c,0x6f,0x6f,0x70,0x44,0x65,0x4c,0x6f,0x6f,0x70,0x28,0x65,0x2c,0x73,0x29,0x7b,0x76,0x61,0x72,0x20,0x61,0x2c,0x6c,0x2c,0x6f,0x3d,0x30,0x3b,0x69,0x73,0x4e,0x61,0x4e,0x28,0x73,0x29,0x26,0x26,0x28,0x73,0x3d,0x31,0x29,0x2c,0x6e,0x75,0x6c,0x6c,0x3d,0x3d,0x65,0x26,0x26,0x28,0x65,0x3d,0x31,0x65,0x33,0x29,0x3b,0x76,0x61,0x72,0x20,0x6e,0x3d,0x73,0x65,0x74,0x49,0x6e,0x74,0x65,0x72,0x76,0x61,0x6c,0x28,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x28,0x29,0x7b,0x6f,0x3e,0x30,0x3f,0x63,0x6c,0x65,0x61,0x72,0x49,0x6e,0x74,0x65,0x72,0x76,0x61,0x6c,0x28,0x6e,0x29,0x3a,0x2b,0x2b,0x73,0x3e,0x31,0x3f,0x6f,0x3d,0x31,0x3a,0x28,0x66,0x65,0x74,0x63,0x68,0x28,0x22,0x2f,0x6a,0x73,0x6f,0x6e,0x3f,0x76,0x69,0x65,0x77,0x3d,0x73,0x65,0x6e,0x73,0x6f,0x72,0x75,0x70,0x64,0x61,0x74,0x65,0x22,0x29,0x2e,0x74,0x68,0x65,0x6e,0x28,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x28,0x73,0x29,0x7b,0x76,0x61,0x72,0x20,0x6f,0x3b,0x32,0x30,0x30,0x3d,0x3d,0x3d,0x73,0x2e,0x73,0x74,0x61,0x74,0x75,0x73,0x3f,0x73,0x2e,0x6a,0x73,0x6f,0x6e,0x28,0x29,0x2e,0x74,0x68,0x65,0x6e,0x28,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x28,0x73,0x29,0x7b,0x66,0x6f,0x72,0x28,0x65,0x3d,0x73,0x2e,0x54,0x54,0x4c,0x2c,0x61,0x3d,0x30,0x3b,0x61,0x3c,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x2e,0x6c,0x65,0x6e,0x67,0x74,0x68,0x3b,0x61,0x2b,0x2b,0x29,0x69,0x66,0x28,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x68,0x61,0x73,0x4f,0x77,0x6e,0x50,0x72,0x6f,0x70,0x65,0x72,0x74,0x79,0x28,0x22,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x22,0x29,0x29,0x66,0x6f,0x72,0x28,0x6c,0x3d,0x30,0x3b,0x6c,0x3c,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x2e,0x6c,0x65,0x6e,0x67,0x74,0x68,0x3b,0x6c,0x2b,0x2b,0x29,0x74,0x72,0x79,0x7b,0x6f,0x3d,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x5b,0x6c,0x5d,0x2e,0x56,0x61,0x6c,0x75,0x65,0x7d,0x63,0x61,0x74,0x63,0x68,0x28,0x65,0x29,0x7b,0x6f,0x3d,0x65,0x2e,0x6e,0x61,0x6d,0x65,0x7d,0x66,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x7b,0x69,0x66,0x28,0x22,0x54,0x79,0x70,0x65,0x45,0x72,0x72,0x6f,0x72,0x22,0x21,0x3d,0x3d,0x6f,0x29,0x7b,0x74,0x65,0x6d,0x70,0x56,0x61,0x6c,0x75,0x65,0x3d,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x5b,0x6c,0x5d,0x2e,0x56,0x61,0x6c,0x75,0x65,0x2c,0x64,0x65,0x63,0x69,0x6d,0x61,0x6c,0x73,0x56,0x61,0x6c,0x75,0x65,0x3d,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x5b,0x6c,0x5d,0x2e,0x4e,0x72,0x44,0x65,0x63,0x69,0x6d,0x61,0x6c,0x73,0x2c,0x74,0x65,0x6d,0x70,0x56,0x61,0x6c,0x75,0x65,0x3d,0x70,0x61,0x72,0x73,0x65,0x46,0x6c,0x6f,0x61,0x74,0x28,0x74,0x65,0x6d,0x70,0x56,0x61,0x6c,0x75,0x65,0x29,0x2e,0x74,0x6f,0x46,0x69,0x78,0x65,0x64,0x28,0x64,0x65,0x63,0x69,0x6d,0x61,0x6c,0x73,0x56,0x61,0x6c,0x75,0x65,0x29,0x3b,0x76,0x61,0x72,0x20,0x72,0x3d,0x22,0x76,0x61,0x6c,0x75,0x65,0x5f,0x22,0x2b,0x28,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x4e,0x75,0x6d,0x62,0x65,0x72,0x2d,0x31,0x29,0x2b,0x22,0x5f,0x22,0x2b,0x28,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x5b,0x6c,0x5d,0x2e,0x56,0x61,0x6c,0x75,0x65,0x4e,0x75,0x6d,0x62,0x65,0x72,0x2d,0x31,0x29,0x2c,0x74,0x3d,0x22,0x76,0x61,0x6c,0x75,0x65,0x6e,0x61,0x6d,0x65,0x5f,0x22,0x2b,0x28,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x4e,0x75,0x6d,0x62,0x65,0x72,0x2d,0x31,0x29,0x2b,0x22,0x5f,0x22,0x2b,0x28,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x5b,0x6c,0x5d,0x2e,0x56,0x61,0x6c,0x75,0x65,0x4e,0x75,0x6d,0x62,0x65,0x72,0x2d,0x31,0x29,0x2c,0x75,0x3d,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x2e,0x67,0x65,0x74,0x45,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x42,0x79,0x49,0x64,0x28,0x72,0x29,0x2c,0x63,0x3d,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x2e,0x67,0x65,0x74,0x45,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x42,0x79,0x49,0x64,0x28,0x74,0x29,0x3b,0x6e,0x75,0x6c,0x6c,0x21,0x3d,0x3d,0x75,0x26,0x26,0x28,0x75,0x2e,0x69,0x6e,0x6e,0x65,0x72,0x48,0x54,0x4d,0x4c,0x3d,0x74,0x65,0x6d,0x70,0x56,0x61,0x6c,0x75,0x65,0x29,0x2c,0x6e,0x75,0x6c,0x6c,0x21,0x3d,0x3d,0x63,0x26,0x26,0x28,0x63,0x2e,0x69,0x6e,0x6e,0x65,0x72,0x48,0x54,0x4d,0x4c,0x3d,0x73,0x2e,0x53,0x65,0x6e,0x73,0x6f,0x72,0x73,0x5b,0x61,0x5d,0x2e,0x54,0x61,0x73,0x6b,0x56,0x61,0x6c,0x75,0x65,0x73,0x5b,0x6c,0x5d,0x2e,0x4e,0x61,0x6d,0x65,0x2b,0x22,0x3a,0x22,0x29,0x7d,0x7d,0x65,0x3d,0x73,0x2e,0x54,0x54,0x4c,0x2c,0x63,0x6c,0x65,0x61,0x72,0x49,0x6e,0x74,0x65,0x72,0x76,0x61,0x6c,0x28,0x6e,0x29,0x2c,0x6c,0x6f,0x6f,0x70,0x44,0x65,0x4c,0x6f,0x6f,0x70,0x28,0x65,0x2c,0x30,0x29,0x7d,0x29,0x3a,0x63,0x6f,0x6e,0x73,0x6f,0x6c,0x65,0x2e,0x6c,0x6f,0x67,0x28,0x22,0x4c,0x6f,0x6f,0x6b,0x73,0x20,0x6c,0x69,0x6b,0x65,0x20,0x74,0x68,0x65,0x72,0x65,0x20,0x77,0x61,0x73,0x20,0x61,0x20,0x70,0x72,0x6f,0x62,0x6c,0x65,0x6d,0x2e,0x20,0x53,0x74,0x61,0x74,0x75,0x73,0x20,0x43,0x6f,0x64,0x65,0x3a,0x20,0x22,0x2b,0x73,0x2e,0x73,0x74,0x61,0x74,0x75,0x73,0x29,0x7d,0x29,0x2e,0x63,0x61,0x74,0x63,0x68,0x28,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x28,0x73,0x29,0x7b,0x63,0x6f,0x6e,0x73,0x6f,0x6c,0x65,0x2e,0x6c,0x6f,0x67,0x28,0x73,0x2e,0x6d,0x65,0x73,0x73,0x61,0x67,0x65,0x29,0x2c,0x65,0x3d,0x35,0x65,0x33,0x2c,0x63,0x6c,0x65,0x61,0x72,0x49,0x6e,0x74,0x65,0x72,0x76,0x61,0x6c,0x28,0x6e,0x29,0x2c,0x6c,0x6f,0x6f,0x70,0x44,0x65,0x4c,0x6f,0x6f,0x70,0x28,0x65,0x2c,0x30,0x29,0x7d,0x29,0x2c,0x6f,0x3d,0x31,0x29,0x7d,0x2c,0x65,0x29,0x7d,0x6c,0x6f,0x6f,0x70,0x44,0x65,0x4c,0x6f,0x6f,0x70,0x28,0x31,0x65,0x33,0x2c,0x30,0x29,0x3b, 0}; diff --git a/static/rules_save.js b/static/rules_save.js new file mode 100644 index 000000000..1b2ccb1fa --- /dev/null +++ b/static/rules_save.js @@ -0,0 +1,36 @@ +function saveRulesFile() { + let button = document.getElementById('save_button'); + let size = document.getElementById('size'); + let ruleTextNew = document.getElementById('rules').value; + ruleTextNew = ruleTextNew.replace(/\\r?\\n/g, '\\r\\n'); + let ruleNumber = document.getElementById('set').value; + let ruleTextFileData = new File([ruleTextNew], 'rules' + ruleNumber + '.txt', { + type: 'text/plain' + }); + let formData = new FormData(); + formData.append('file', ruleTextFileData); + formData.append('enctype', 'multipart/form-data'); + let url = '/rules' + ruleNumber + '.txt?callback=' + Date.now(); + fetch(url).then(res => res.text()).then((ruleTextOld) => { + if (ruleTextNew === ruleTextOld) { + console.log('nothing to save...'); + } else { + let url = '/upload'; + fetch(url, { + method: 'POST', + body: formData + }).then( + response => response.text()).then(html => { + let url = '/rules' + ruleNumber + '.txt?callback=' + Date.now(); + fetch(url).then(res => res.text()).then((ruleTextNewCheck) => { + if (ruleTextNew === ruleTextNewCheck) { + toasting(); + size.innerHTML = ruleTextNew.length; + } else { + console.log('error when saving...'); + } + }); + }); + } + }); +}; From 06b44380030acd9830b878b84c797de32f0f7b44 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 18 Mar 2020 18:09:23 +0100 Subject: [PATCH 10/40] [I2C] Add I2C frequency setting For I2C UART an I2C clock of 400 kHz is needed to be able to handle continuous streams of data. But the default was still 100 kHz, unless you selected a plugin that may have set the I2C frequency to 400 kHz like the Framed OLED plugin. --- src/Custom-sample.h | 1 + src/ESPEasyStorage.ino | 3 ++ src/ESPEasy_buildinfo.h | 2 +- src/ESPEasy_checks.ino | 2 +- src/Hardware.ino | 67 ++++++++++++++------------ src/Misc.ino | 1 + src/WebServer_HardwarePage.ino | 11 ++++- src/_P082_GPS.ino | 2 +- src/src/DataStructs/ESPEasyDefaults.h | 3 ++ src/src/DataStructs/SettingsStruct.cpp | 2 + src/src/DataStructs/SettingsStruct.h | 1 + 11 files changed, 60 insertions(+), 35 deletions(-) diff --git a/src/Custom-sample.h b/src/Custom-sample.h index 573ed98bd..2319d686f 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -96,6 +96,7 @@ #define DEFAULT_PIN_I2C_SDA 4 #define DEFAULT_PIN_I2C_SCL 5 +#define DEFAULT_I2C_CLOCK_SPEED 400000 // Use 100 kHz if working with old I2C chips #define DEFAULT_PIN_STATUS_LED (-1) #define DEFAULT_PIN_STATUS_LED_INVERSED true diff --git a/src/ESPEasyStorage.ino b/src/ESPEasyStorage.ino index f43354ba2..9e9d5a299 100644 --- a/src/ESPEasyStorage.ino +++ b/src/ESPEasyStorage.ino @@ -149,6 +149,9 @@ String BuildFixes() Settings.ResetFactoryDefaultPreference = 0; Settings.OldRulesEngine(DEFAULT_RULES_OLDENGINE); } + if (Settings.Build < 20105) { + Settings.I2C_clockSpeed = 400000; + } Settings.Build = BUILD; return SaveSettings(); diff --git a/src/ESPEasy_buildinfo.h b/src/ESPEasy_buildinfo.h index f8b2e1fb6..baaeaa71f 100644 --- a/src/ESPEasy_buildinfo.h +++ b/src/ESPEasy_buildinfo.h @@ -20,7 +20,7 @@ #endif // if defined(ESP32) -#define BUILD 20104 // git version e.g. "20103" can be read as "2.1.03" (stored in int16_t) +#define BUILD 20105 // git version e.g. "20103" can be read as "2.1.03" (stored in int16_t) #if defined(ESP8266) # define BUILD_NOTES " - Mega" #endif // if defined(ESP8266) diff --git a/src/ESPEasy_checks.ino b/src/ESPEasy_checks.ino index 700a7b1dc..ea444e1b8 100644 --- a/src/ESPEasy_checks.ino +++ b/src/ESPEasy_checks.ino @@ -34,7 +34,7 @@ template constexpr size_t offsetOf(U T::*member) void run_compiletime_checks() { check_size(); check_size(); - const unsigned int SettingsStructSize = (244 + 82 * TASKS_MAX); + const unsigned int SettingsStructSize = (248 + 82 * TASKS_MAX); check_size(); check_size(); check_size(); diff --git a/src/Hardware.ino b/src/Hardware.ino index 61c52e89e..f6e53bc73 100644 --- a/src/Hardware.ino +++ b/src/Hardware.ino @@ -49,11 +49,47 @@ void hardwareInit() pinMode(Settings.Pin_Reset, INPUT_PULLUP); } + initI2C(); + + // SPI Init + if (Settings.InitSPI) + { + SPI.setHwCs(false); + SPI.begin(); + String log = F("INIT : SPI Init (without CS)"); + addLog(LOG_LEVEL_INFO, log); + } + else + { + String log = F("INIT : SPI not enabled"); + addLog(LOG_LEVEL_INFO, log); + } + +#ifdef FEATURE_SD + + if (Settings.Pin_sd_cs >= 0) + { + if (SD.begin(Settings.Pin_sd_cs)) + { + String log = F("SD : Init OK"); + addLog(LOG_LEVEL_INFO, log); + } + else + { + String log = F("SD : Init failed"); + addLog(LOG_LEVEL_ERROR, log); + } + } +#endif // ifdef FEATURE_SD +} + +void initI2C() { // configure hardware pins according to eeprom settings. if (Settings.Pin_i2c_sda != -1) { String log = F("INIT : I2C"); addLog(LOG_LEVEL_INFO, log); + Wire.setClock(Settings.I2C_clockSpeed); Wire.begin(Settings.Pin_i2c_sda, Settings.Pin_i2c_scl); if (Settings.WireClockStretchLimit) @@ -90,37 +126,6 @@ void hardwareInit() } } } - - // SPI Init - if (Settings.InitSPI) - { - SPI.setHwCs(false); - SPI.begin(); - String log = F("INIT : SPI Init (without CS)"); - addLog(LOG_LEVEL_INFO, log); - } - else - { - String log = F("INIT : SPI not enabled"); - addLog(LOG_LEVEL_INFO, log); - } - -#ifdef FEATURE_SD - - if (Settings.Pin_sd_cs >= 0) - { - if (SD.begin(Settings.Pin_sd_cs)) - { - String log = F("SD : Init OK"); - addLog(LOG_LEVEL_INFO, log); - } - else - { - String log = F("SD : Init failed"); - addLog(LOG_LEVEL_ERROR, log); - } - } -#endif // ifdef FEATURE_SD } void checkResetFactoryPin() { diff --git a/src/Misc.ino b/src/Misc.ino index 6b40445fb..6a52fadb2 100644 --- a/src/Misc.ino +++ b/src/Misc.ino @@ -1224,6 +1224,7 @@ void ResetFactory() Settings.ConnectionFailuresThreshold = DEFAULT_CON_FAIL_THRES; Settings.WireClockStretchLimit = DEFAULT_I2C_CLOCK_LIMIT; */ + Settings.I2C_clockSpeed = DEFAULT_I2C_CLOCK_SPEED; #ifdef PLUGIN_DESCR strcpy_P(Settings.Name, PSTR(PLUGIN_DESCR)); diff --git a/src/WebServer_HardwarePage.ino b/src/WebServer_HardwarePage.ino index e0cac1262..14ba03f6f 100644 --- a/src/WebServer_HardwarePage.ino +++ b/src/WebServer_HardwarePage.ino @@ -18,6 +18,7 @@ void handle_hardware() { Settings.Pin_Reset = getFormItemInt(F("pres")); Settings.Pin_i2c_sda = getFormItemInt(F("psda")); Settings.Pin_i2c_scl = getFormItemInt(F("pscl")); + Settings.I2C_clockSpeed = getFormItemInt(F("pi2csp"), DEFAULT_I2C_CLOCK_SPEED); Settings.InitSPI = isFormItemChecked(F("initspi")); // SPI Init Settings.Pin_sd_cs = getFormItemInt(F("sd")); int gpio = 0; @@ -38,7 +39,12 @@ void handle_hardware() { } ++gpio; } - addHtmlError(SaveSettings()); + String error = SaveSettings(); + addHtmlError(error); + if (error.length() == 0) { + // Apply I2C settings. + initI2C(); + } } addHtml(F("")); @@ -57,6 +63,9 @@ void handle_hardware() { addFormSubHeader(F("I2C Interface")); addFormPinSelectI2C(formatGpioName_bidirectional("SDA"), F("psda"), Settings.Pin_i2c_sda); addFormPinSelectI2C(formatGpioName_output("SCL"), F("pscl"), Settings.Pin_i2c_scl); + addFormNumericBox(F("Clock Speed"), F("pi2csp"), Settings.I2C_clockSpeed, 100, 3400000); + addUnit(F("Hz")); + addFormNote(F("Use 100 kHz for old I2C devices, 400 kHz is max for most.")); // SPI Init addFormSubHeader(F("SPI Interface")); diff --git a/src/_P082_GPS.ino b/src/_P082_GPS.ino index e539e99e9..d072010f1 100644 --- a/src/_P082_GPS.ino +++ b/src/_P082_GPS.ino @@ -63,7 +63,7 @@ #define P082_QUERY4_DFLT P082_QUERY_SPD -// #define P082_SEND_GPS_TO_LOG +#define P082_SEND_GPS_TO_LOG struct P082_data_struct : public PluginTaskData_base { P082_data_struct() : gps(nullptr), P082_easySerial(nullptr) {} diff --git a/src/src/DataStructs/ESPEasyDefaults.h b/src/src/DataStructs/ESPEasyDefaults.h index 26431df32..b1e9ed9f4 100644 --- a/src/src/DataStructs/ESPEasyDefaults.h +++ b/src/src/DataStructs/ESPEasyDefaults.h @@ -153,6 +153,9 @@ #ifndef DEFAULT_PIN_I2C_SCL #define DEFAULT_PIN_I2C_SCL 5 #endif +#ifndef DEFAULT_I2C_CLOCK_SPEED +#define DEFAULT_I2C_CLOCK_SPEED 400000 // Use 100 kHz if working with old I2C chips +#endif #ifndef DEFAULT_PIN_STATUS_LED #define DEFAULT_PIN_STATUS_LED (-1) diff --git a/src/src/DataStructs/SettingsStruct.cpp b/src/src/DataStructs/SettingsStruct.cpp index 96da2a3ba..1cab7e24d 100644 --- a/src/src/DataStructs/SettingsStruct.cpp +++ b/src/src/DataStructs/SettingsStruct.cpp @@ -123,6 +123,7 @@ void SettingsStruct_tmpl::validate() { if (VariousBits1 > (1 << 30)) { VariousBits1 = 0; } ZERO_TERMINATE(Name); ZERO_TERMINATE(NTPHost); + if (I2C_clockSpeed == 0 || I2C_clockSpeed > 3400000) { I2C_clockSpeed = DEFAULT_I2C_CLOCK_SPEED; } } template @@ -215,6 +216,7 @@ void SettingsStruct_tmpl::clearMisc() { UseSerial = true; UseSSDP = false; WireClockStretchLimit = 0; + I2C_clockSpeed = 400000; GlobalSync = false; ConnectionFailuresThreshold = 0; MQTTRetainFlag = false; diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index 7d7c24a43..ab53d89ca 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -169,6 +169,7 @@ class SettingsStruct_tmpl float Longitude; uint32_t VariousBits1; uint32_t ResetFactoryDefaultPreference; // Do not clear this one in the clearAll() + uint32_t I2C_clockSpeed; // FIXME @TD-er: As discussed in #1292, the CRC for the settings is now disabled. // make sure crc is the last value in the struct From 023c97d547c225041541eac10c4df4629a0e4e11 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 19 Mar 2020 10:38:24 +0100 Subject: [PATCH 11/40] ESPEasy Status LED is not working on ESP32 with buildin LED (#2940) Fixes: #2940 Copy-paste fix from @thomastech https://github.com/letscontrolit/ESPEasy/issues/2940#issuecomment-599627656 --- src/Misc.ino | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Misc.ino b/src/Misc.ino index 6a52fadb2..5de27bb46 100644 --- a/src/Misc.ino +++ b/src/Misc.ino @@ -756,7 +756,10 @@ void statusLED(bool traffic) #if defined(ESP8266) analogWrite(Settings.Pin_status_led, pwm); - #endif + #endif // if defined(ESP8266) + #if defined(ESP32) + analogWriteESP32(Settings.Pin_status_led, pwm); + #endif // if defined(ESP32) } } From 7d4dd2355a0e0650473f7ff223a1ed06f7710891 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 19 Mar 2020 18:09:17 +0100 Subject: [PATCH 12/40] Pulse Counter must retain its values after reboot (#2268) Fixes #2268 --- src/_P003_Pulse.ino | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/_P003_Pulse.ino b/src/_P003_Pulse.ino index 9f807a75d..17277ab95 100644 --- a/src/_P003_Pulse.ino +++ b/src/_P003_Pulse.ino @@ -138,6 +138,39 @@ boolean Plugin_003(byte function, struct EventStruct *event, String& string) addLog(LOG_LEVEL_INFO,log); pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP); success = Plugin_003_pulseinit(Settings.TaskDevicePin1[event->TaskIndex], event->TaskIndex,Settings.TaskDevicePluginConfig[event->TaskIndex][2]); + + // Restore any value that may have been read from the RTC. + Plugin_003_pulseCounter[event->TaskIndex] = UserVar[event->BaseVarIndex]; + Plugin_003_pulseTotalCounter[event->TaskIndex] = UserVar[event->BaseVarIndex+1]; + Plugin_003_pulseTime[event->TaskIndex] = UserVar[event->BaseVarIndex+2]; + + switch (Settings.TaskDevicePluginConfig[event->TaskIndex][1]) + { + case 0: + { + Plugin_003_pulseCounter[event->TaskIndex] = UserVar[event->BaseVarIndex]; + break; + } + case 1: + { + Plugin_003_pulseCounter[event->TaskIndex] = UserVar[event->BaseVarIndex]; + Plugin_003_pulseTotalCounter[event->TaskIndex] = UserVar[event->BaseVarIndex+1]; + Plugin_003_pulseTime[event->TaskIndex] = UserVar[event->BaseVarIndex+2]; + break; + } + case 2: + { + Plugin_003_pulseTotalCounter[event->TaskIndex] = UserVar[event->BaseVarIndex]; + break; + } + case 3: + { + Plugin_003_pulseCounter[event->TaskIndex] = UserVar[event->BaseVarIndex]; + Plugin_003_pulseTotalCounter[event->TaskIndex] = UserVar[event->BaseVarIndex+1]; + break; + } + } + break; } From b11043243fa4f8c9673eaf1fadfd891e8eb9680d Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 19 Mar 2020 18:21:47 +0100 Subject: [PATCH 13/40] [Build] Disable test_ESP8266_4M1M_VCC_MDNS_SD due to max sketch size Temporary disabled so we can make a nightly build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e46add827..0b0926b69 100644 --- a/.travis.yml +++ b/.travis.yml @@ -69,7 +69,7 @@ script: - PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e test_ESP32-wrover-kit_4M316k - PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e test_ESP32_4M316k - PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e test_ESP8266_4M1M_VCC - - PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e test_ESP8266_4M1M_VCC_MDNS_SD + #- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e test_ESP8266_4M1M_VCC_MDNS_SD #- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e test_beta_ESP8266_16M - PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -e test_beta_ESP8266_4M1M From 563b1da419ce8e587dc037d84fd283bf0d2c41f8 Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 19 Mar 2020 23:48:59 +0100 Subject: [PATCH 14/40] Fix resetpulsecounter for P003_Pulse (#2710) Fixes: #2710 I really need to make sense of the argument positions as this is really error prone as shown here. --- src/_P003_Pulse.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_P003_Pulse.ino b/src/_P003_Pulse.ino index 17277ab95..67e6bd324 100644 --- a/src/_P003_Pulse.ino +++ b/src/_P003_Pulse.ino @@ -221,7 +221,7 @@ boolean Plugin_003(byte function, struct EventStruct *event, String& string) if (command == F("resetpulsecounter")) { // Allow for an optional taskIndex parameter. When not given it will take the first task with this plugin. - const taskIndex_t taskIndex = parseCommandArgumentTaskIndex(string, 2); + const taskIndex_t taskIndex = parseCommandArgumentTaskIndex(string, 1); if (validTaskIndex(taskIndex)) { if (event->TaskIndex != taskIndex) { break; From efa41ecc3ba4a2b2fe98e6df66dba2dbdaaf77c8 Mon Sep 17 00:00:00 2001 From: TD-er Date: Fri, 20 Mar 2020 00:34:59 +0100 Subject: [PATCH 15/40] [Blynk] Fix building C015 Blynk controller As found [on the forum](https://www.letscontrolit.com/forum/viewtopic.php?f=6&t=7538) --- src/_C015.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_C015.ino b/src/_C015.ino index 57b42c0da..b0d4a390b 100644 --- a/src/_C015.ino +++ b/src/_C015.ino @@ -341,7 +341,7 @@ String Command_Blynk_Set_c015(struct EventStruct *event, const char* Line){ return err; } - String data = parseString(Line, 3, true, false); + String data = parseString(Line, 3); if (data.length() == 0){ String err = F("Skip sending empty data to blynk vPin "); From 0f8ef96484212be263accb62a2105eae9effe0f9 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 21 Mar 2020 11:09:44 +0100 Subject: [PATCH 16/40] [JSON] Fix JSON output of values for single task Generated JSON had trailing TTL value which rendered it invalid JSON. --- src/WebServer_JSON.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WebServer_JSON.ino b/src/WebServer_JSON.ino index aff0d68c4..5625d65dd 100644 --- a/src/WebServer_JSON.ino +++ b/src/WebServer_JSON.ino @@ -241,8 +241,8 @@ void handle_json() if (!showSpecificTask) { addHtml(F("],\n")); + stream_last_json_object_value(F("TTL"), String(lowest_ttl_json * 1000)); } - stream_last_json_object_value(F("TTL"), String(lowest_ttl_json * 1000)); TXBuffer.endStream(); } From fb34e892bbce20643af06eab6020a194145e565d Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 11 Mar 2020 21:52:58 +0100 Subject: [PATCH 17/40] [SerialProxy] Add regexp filtering --- src/ESPEasyStorage.ino | 134 +++++++++++++++++++++++++++++++++----- src/WebServer_Rules.ino | 2 +- src/_P087_SerialProxy.ino | 128 +++++++++++++++++++++++++++++------- 3 files changed, 225 insertions(+), 39 deletions(-) diff --git a/src/ESPEasyStorage.ino b/src/ESPEasyStorage.ino index f43354ba2..e4d35380b 100644 --- a/src/ESPEasyStorage.ino +++ b/src/ESPEasyStorage.ino @@ -601,6 +601,77 @@ String SaveCustomTaskSettings(taskIndex_t TaskIndex, byte *memAddress, int datas return SaveToFile(CustomTaskSettings_Type, TaskIndex, (char *)FILE_CONFIG, memAddress, datasize); } +/********************************************************************************************\ + Save array of Strings to Custom Task settings + Use maxStringLength = 0 to optimize for size (strings will be concatenated) + \*********************************************************************************************/ +String SaveCustomTaskSettings(taskIndex_t TaskIndex, String strings[], uint16_t nrStrings, uint16_t maxStringLength) +{ + checkRAM(F("SaveCustomTaskSettings")); + const uint16_t bufferSize = 128; + + // FIXME TD-er: For now stack allocated, may need to be heap allocated? + byte buffer[bufferSize]; + + String result; + int writePos = 0; + uint16_t stringCount = 0; + uint16_t stringReadPos = 0; + uint16_t nextStringPos = 0; + uint16_t curStringLength = 0; + + if (maxStringLength != 0) { + // Specified string length, check given strings + for (int i = 0; i < nrStrings; ++i) { + if (strings[i].length() >= maxStringLength) { + result += getCustomTaskSettingsError(i); + } + } + } + while (stringCount < nrStrings && writePos < DAT_TASKS_CUSTOM_SIZE) { + ZERO_FILL(buffer); + for (int i = 0; i < bufferSize && stringCount < nrStrings; ++i) { + if (stringReadPos == 0) { + // We're at the start of a string + curStringLength = strings[stringCount].length(); + if (maxStringLength != 0) { + if (curStringLength >= maxStringLength) { + curStringLength = maxStringLength - 1; + } + } + } + + uint16_t curPos = writePos + i; + if (curPos >= nextStringPos) { + if (stringReadPos < curStringLength) { + buffer[i] = strings[stringCount][stringReadPos]; + ++stringReadPos; + } else { + buffer[i] = 0; + stringReadPos = 0; + ++stringCount; + if (maxStringLength == 0) { + nextStringPos += curStringLength + 1; + } else { + nextStringPos += maxStringLength; + } + } + } + } + // Buffer is filled, now write to flash + // As we write in parts, only count as single write. + if (RTC.flashDayCounter > 0) { + --RTC.flashDayCounter; + } + result += SaveToFile(CustomTaskSettings_Type, TaskIndex, (char *)FILE_CONFIG, &(buffer[0]), bufferSize, writePos); + writePos += bufferSize; + } + if (writePos >= DAT_TASKS_CUSTOM_SIZE && stringCount < nrStrings) { + result += F("Error: Not all strings fit in custom task settings."); + } + return result; +} + String getCustomTaskSettingsError(byte varNr) { String error = F("Error: Text too long for line "); @@ -632,26 +703,55 @@ String LoadCustomTaskSettings(taskIndex_t TaskIndex, byte *memAddress, int datas /********************************************************************************************\ Load array of Strings from Custom Task settings + Use maxStringLength = 0 to optimize for size (strings will be concatenated) \*********************************************************************************************/ -String LoadCustomTaskSettings(taskIndex_t TaskIndex, String strings[], uint16_t nrStrings, uint16_t maxStringLenght) +String LoadCustomTaskSettings(taskIndex_t TaskIndex, String strings[], uint16_t nrStrings, uint16_t maxStringLength) { START_TIMER; checkRAM(F("LoadCustomTaskSettings")); - // FIXME TD-er: For now stack allocated, may need to be heap allocated? - if (maxStringLenght >= 128) { return F("Max 128 chars allowed"); } - char tmpStr[128]; - String result; + const uint16_t bufferSize = 128; - for (int i = 0; i < nrStrings; ++i) { + // FIXME TD-er: For now stack allocated, may need to be heap allocated? + if (maxStringLength >= bufferSize) { return F("Max 128 chars allowed"); } + char buffer[bufferSize]; + + String result; + uint16_t readPos = 0; + uint16_t nextStringPos = 0; + uint16_t stringCount = 0; + String tmpString; + tmpString.reserve(bufferSize); + while (stringCount < nrStrings && readPos < DAT_TASKS_CUSTOM_SIZE) { result += LoadFromFile(CustomTaskSettings_Type, TaskIndex, (char *)FILE_CONFIG, - (byte *)&tmpStr, - maxStringLenght, - maxStringLenght * i); - tmpStr[maxStringLenght] = 0; // Terminate in case of uninitalized data - strings[i] = String(tmpStr); + (byte *)&buffer, + bufferSize, + readPos); + for (int i = 0; i < bufferSize && stringCount < nrStrings; ++i) { + uint16_t curPos = readPos + i; + if (curPos >= nextStringPos) { + if (buffer[i] == 0) { + if (maxStringLength != 0) { + // Specific string length, so we have to set the next string position. + nextStringPos += maxStringLength; + } + strings[stringCount] = tmpString; + tmpString = ""; + tmpString.reserve(bufferSize); + ++stringCount; + } else { + tmpString += buffer[i]; + } + } + } + readPos += bufferSize; + } + if (tmpString.length() != 0 && stringCount < nrStrings) { + result += F("Incomplete custom settings for task "); + result += (TaskIndex + 1); + strings[stringCount] = tmpString; } STOP_TIMER(LOAD_CUSTOM_TASK_STATS); return result; @@ -758,11 +858,11 @@ String InitFile(const char *fname, int datasize) \*********************************************************************************************/ String SaveToFile(const char *fname, int index, const byte *memAddress, int datasize) { - return SaveToFile(fname, index, memAddress, datasize, "r+"); + return doSaveToFile(fname, index, memAddress, datasize, "r+"); } // See for mode description: https://github.com/esp8266/Arduino/blob/master/doc/filesystem.rst -String SaveToFile(const char *fname, int index, const byte *memAddress, int datasize, const char* mode) +String doSaveToFile(const char *fname, int index, const byte *memAddress, int datasize, const char* mode) { #ifndef ESP32 @@ -962,6 +1062,10 @@ String LoadFromFile(SettingsType settingsType, int index, char *fname, byte *mem } String SaveToFile(SettingsType settingsType, int index, char *fname, byte *memAddress, int datasize) { + return SaveToFile(settingsType, index, fname, memAddress, datasize, 0); +} + +String SaveToFile(SettingsType settingsType, int index, char *fname, byte *memAddress, int datasize, int posInBlock) { bool read = false; int offset, max_size; @@ -969,10 +1073,10 @@ String SaveToFile(SettingsType settingsType, int index, char *fname, byte *memAd return getSettingsFileIndexRangeError(read, settingsType, index); } - if (datasize > max_size) { + if (datasize > max_size || (posInBlock + datasize) > max_size) { return getSettingsFileDatasizeError(read, settingsType, index, datasize, max_size); } - return SaveToFile(fname, offset, memAddress, datasize); + return SaveToFile(fname, offset + posInBlock, memAddress, datasize); } String ClearInFile(SettingsType settingsType, int index, char *fname) { diff --git a/src/WebServer_Rules.ino b/src/WebServer_Rules.ino index aa130ab3c..264e869a4 100644 --- a/src/WebServer_Rules.ino +++ b/src/WebServer_Rules.ino @@ -52,7 +52,7 @@ void handle_rules() { } else { // Save as soon as possible, as the webserver may already overwrite the args. const byte *memAddress = reinterpret_cast(web_server.arg(F("rules")).c_str()); - error = SaveToFile(fileName.c_str(), 0, memAddress, rulesLength, "w"); + error = doSaveToFile(fileName.c_str(), 0, memAddress, rulesLength, "w"); } } else { error = F("Error: Data was not saved, rules argument missing or corrupted"); diff --git a/src/_P087_SerialProxy.ino b/src/_P087_SerialProxy.ino index e08694a57..d99106bfc 100644 --- a/src/_P087_SerialProxy.ino +++ b/src/_P087_SerialProxy.ino @@ -10,6 +10,7 @@ #include #include "_Plugin_Helper.h" +#include #define PLUGIN_087 #define PLUGIN_ID_087 87 @@ -27,8 +28,8 @@ #define P087_DEFAULT_BAUDRATE 38400 -#define P87_Nlines 2 -#define P87_Nchars 64 +#define P87_Nlines 9 +#define P87_Nchars 128 #define P087_INITSTRING 0 #define P087_EXITSTRING 1 @@ -145,6 +146,47 @@ struct P087_data_struct : public PluginTaskData_base { max_length = maxlenght; } + void loadLines(taskIndex_t taskIndex) { + LoadCustomTaskSettings(taskIndex, _lines, P87_Nlines, 0); + } + + String getLine(uint8_t lineNr) const { + if (lineNr < P87_Nlines) { + return _lines[lineNr]; + } + return ""; + } + + bool matchRegexp(uint8_t lineNr, String& received) const { + if (lineNr >= P87_Nlines) { return false; } + size_t strlength = received.length(); + + if (strlength == 0) { + return false; + } + + if ((regexp_match_length > 0) && (strlength > regexp_match_length)) { + strlength = regexp_match_length; + } + + // We need to do a const_cast here, but this only is valid as long as we + // don't call a replace function from regexp. + MatchState ms(const_cast(received.c_str()), strlength); + char result = ms.Match(_lines[lineNr].c_str()); + + if (result == REGEXP_MATCHED) { + if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { + String log = F("Match at: "); + log += ms.MatchStart; + log += F(" Match Length: "); + log += ms.MatchLength; + addLog(LOG_LEVEL_DEBUG, log); + } + return true; + } + return false; + } + private: bool max_length_reached() const { @@ -152,12 +194,15 @@ private: return sentence_part.length() >= max_length; } + String _lines[P87_Nlines]; + ESPeasySerial *P087_easySerial = nullptr; String sentence_part; uint16_t max_length = 550; uint32_t sentences_received = 0; uint32_t sentences_received_error = 0; uint32_t length_last_received = 0; + uint32_t regexp_match_length = 0; }; @@ -289,15 +334,21 @@ boolean Plugin_087(byte function, struct EventStruct *event, String& string) { } */ - { - String strings[P87_Nlines]; - LoadCustomTaskSettings(event->TaskIndex, strings, P87_Nlines, P87_Nchars); + P087_data_struct *P087_data = + static_cast(getPluginTaskData(event->TaskIndex)); + if ((nullptr != P087_data)) { for (byte varNr = 0; varNr < P87_Nlines; varNr++) { - String label = F("Init "); - label += String(varNr + 1); - addFormTextBox(label, getPluginCustomArgName(varNr), strings[varNr], P87_Nchars); + String label; + + if (varNr == 0) { + label = F("Init"); + } else { + label = F("Filter"); + label += String(varNr); + } + addFormTextBox(label, getPluginCustomArgName(varNr), P087_data->getLine(varNr), P87_Nchars); } } @@ -312,20 +363,13 @@ boolean Plugin_087(byte function, struct EventStruct *event, String& string) { serialHelper_webformSave(event); P087_BAUDRATE = getFormItemInt(P087_BAUDRATE_LABEL); - String error; - char P087_deviceTemplate[P87_Nlines][P87_Nchars]; + String lines[P87_Nlines]; for (byte varNr = 0; varNr < P87_Nlines; varNr++) { - if (!safe_strncpy(P087_deviceTemplate[varNr], web_server.arg(getPluginCustomArgName(varNr)), P87_Nchars)) { - error += getCustomTaskSettingsError(varNr); - } + lines[varNr] = web_server.arg(getPluginCustomArgName(varNr)); } - - if (error.length() > 0) { - addHtmlError(error); - } - SaveCustomTaskSettings(event->TaskIndex, (byte *)&P087_deviceTemplate, sizeof(P087_deviceTemplate)); + addHtmlError(SaveCustomTaskSettings(event->TaskIndex, lines, P87_Nlines, 0)); success = true; break; @@ -343,6 +387,7 @@ boolean Plugin_087(byte function, struct EventStruct *event, String& string) { } if (P087_data->init(serial_rx, serial_tx, P087_BAUDRATE)) { + P087_data->loadLines(event->TaskIndex); success = true; if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { @@ -374,7 +419,13 @@ boolean Plugin_087(byte function, struct EventStruct *event, String& string) { delay(0); // Processing a full sentence may take a while, run some // background tasks. P087_data->getSentence(event->String2); - sendData(event); + + if (event->String2.length() > 0) { + if (Plugin_087_match_all(event->TaskIndex, event->String2)) { + sendData(event); + addLog(LOG_LEVEL_INFO, event->String2); + } + } } success = true; } @@ -386,17 +437,48 @@ boolean Plugin_087(byte function, struct EventStruct *event, String& string) { static_cast(getPluginTaskData(event->TaskIndex)); if ((nullptr != P087_data)) { - String strings[P87_Nlines]; - LoadCustomTaskSettings(event->TaskIndex, strings, P87_Nlines, P87_Nchars); - parseSystemVariables(strings[0], false); - P087_data->sendString(strings[0]); + String initstr = P087_data->getLine(0); + parseSystemVariables(initstr, false); + P087_data->sendString(initstr); } break; } + + case PLUGIN_WRITE: { + String cmd = parseString(string, 1); + + + if (cmd.equalsIgnoreCase(F("serialproxy_write"))) { + P087_data_struct *P087_data = + static_cast(getPluginTaskData(event->TaskIndex)); + + if ((nullptr != P087_data)) { + String param1 = parseString(string, 2); + parseSystemVariables(param1, false); + P087_data->sendString(param1); + addLog(LOG_LEVEL_INFO, param1); + success = true; + } + } + + break; + } } return success; } +bool Plugin_087_match_all(taskIndex_t taskIndex, String& received) +{ + P087_data_struct *P087_data = + static_cast(getPluginTaskData(taskIndex)); + + if ((nullptr == P087_data)) { + return false; + } + + return P087_data->matchRegexp(1, received); +} + String Plugin_087_valuename(byte value_nr, bool displayString) { switch (value_nr) { case P087_QUERY_VALUE: return displayString ? F("Value") : F("v"); From ef2de3a8945cac2f44e082b3da095008ed5dfc58 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 11 Mar 2020 21:53:15 +0100 Subject: [PATCH 18/40] [Lib] Add RegExp lib --- lib/Regexp/README.md | 14 + lib/Regexp/Regexp.h | 1 + .../examples/GlobalMatch/GlobalMatch.pde | 52 ++ .../examples/GlobalReplace/GlobalReplace.pde | 61 ++ .../GlobalReplace_Entities.pde | 45 ++ lib/Regexp/examples/Match/Match.pde | 29 + lib/Regexp/examples/MatchCount/MatchCount.pde | 23 + lib/Regexp/keywords.txt | 9 + lib/Regexp/library.properties | 9 + lib/Regexp/src/Regexp.cpp | 732 ++++++++++++++++++ lib/Regexp/src/Regexp.h | 131 ++++ 11 files changed, 1106 insertions(+) create mode 100644 lib/Regexp/README.md create mode 100644 lib/Regexp/Regexp.h create mode 100644 lib/Regexp/examples/GlobalMatch/GlobalMatch.pde create mode 100644 lib/Regexp/examples/GlobalReplace/GlobalReplace.pde create mode 100644 lib/Regexp/examples/GlobalReplace_Entities/GlobalReplace_Entities.pde create mode 100644 lib/Regexp/examples/Match/Match.pde create mode 100644 lib/Regexp/examples/MatchCount/MatchCount.pde create mode 100644 lib/Regexp/keywords.txt create mode 100644 lib/Regexp/library.properties create mode 100644 lib/Regexp/src/Regexp.cpp create mode 100644 lib/Regexp/src/Regexp.h diff --git a/lib/Regexp/README.md b/lib/Regexp/README.md new file mode 100644 index 000000000..0f5551a3f --- /dev/null +++ b/lib/Regexp/README.md @@ -0,0 +1,14 @@ +Regexp +====== + +Regular expression parser for microcontrollers based on the Lua one. + +Documentation on interfacing with the library, and other details at: + +http://www.gammon.com.au/forum/?id=11063 + +## Documentation on regular expressions (Lua patterns) + +* [Official Lua documentation](http://www.lua.org/manual/5.2/manual.html#6.4.1) + +* [Simplified documentation from MUSHclient help](http://www.gammon.com.au/scripts/doc.php?lua=string.find) diff --git a/lib/Regexp/Regexp.h b/lib/Regexp/Regexp.h new file mode 100644 index 000000000..7c462a503 --- /dev/null +++ b/lib/Regexp/Regexp.h @@ -0,0 +1 @@ +#include "src/Regexp.h" diff --git a/lib/Regexp/examples/GlobalMatch/GlobalMatch.pde b/lib/Regexp/examples/GlobalMatch/GlobalMatch.pde new file mode 100644 index 000000000..b252aa468 --- /dev/null +++ b/lib/Regexp/examples/GlobalMatch/GlobalMatch.pde @@ -0,0 +1,52 @@ +#include + +// called for each match +void match_callback (const char * match, // matching string (not null-terminated) + const unsigned int length, // length of matching string + const MatchState & ms) // MatchState in use (to get captures) +{ +char cap [10]; // must be large enough to hold captures + + Serial.print ("Matched: "); + Serial.write ((byte *) match, length); + Serial.println (); + + for (byte i = 0; i < ms.level; i++) + { + Serial.print ("Capture "); + Serial.print (i, DEC); + Serial.print (" = "); + ms.GetCapture (cap, i); + Serial.println (cap); + } // end of for each capture + +} // end of match_callback + + +void setup () +{ + Serial.begin (115200); + Serial.println (); + unsigned long count; + + // what we are searching (the target) + char buf [100] = "The quick brown fox jumps over the lazy wolf"; + + // match state object + MatchState ms (buf); + + // original buffer + Serial.println (buf); + + // search for three letters followed by a space (two captures) + count = ms.GlobalMatch ("(%a+)( )", match_callback); + + // show results + Serial.print ("Found "); + Serial.print (count); // 8 in this case + Serial.println (" matches."); + + +} // end of setup + +void loop () {} \ No newline at end of file diff --git a/lib/Regexp/examples/GlobalReplace/GlobalReplace.pde b/lib/Regexp/examples/GlobalReplace/GlobalReplace.pde new file mode 100644 index 000000000..179b1d94f --- /dev/null +++ b/lib/Regexp/examples/GlobalReplace/GlobalReplace.pde @@ -0,0 +1,61 @@ +#include + +// called for every match +void replace_callback (const char * match, // what we found + const unsigned int length, // how long it was + const char * & replacement, // put replacement here + unsigned int & replacement_length, // put replacement length here + const MatchState & ms) // for looking up captures +{ + + // show matching text + Serial.print("Match = "); + Serial.write((byte *) match, length); + Serial.println (); + + replacement = "Nick"; + replacement_length = 4; +} // end of replace_callback + +void setup () +{ + Serial.begin (115200); + Serial.println (); + unsigned long count; + + // what we are searching (the target) + char buf [100] = "The quick brown fox jumps over the lazy wolf"; + + // match state object + MatchState ms (buf); + + // original buffer + Serial.println (buf); + + // search for three letters + count = ms.GlobalReplace ("%a+", replace_callback); + + // show results + Serial.print ("Converted string: "); + Serial.println (buf); + Serial.print ("Found "); + Serial.print (count); // 9 in this case + Serial.println (" matches."); + + // copy in new target + strcpy (buf, "But does it get goat's blood out?"); + ms.Target (buf); // recompute length + + // replace vowels with * + count = ms.GlobalReplace ("[aeiou]", "*"); + + // show results + Serial.print ("Converted string: "); + Serial.println (buf); + Serial.print ("Found "); + Serial.print (count); // 13 in this case + Serial.println (" matches."); + +} // end of setup + +void loop () {} diff --git a/lib/Regexp/examples/GlobalReplace_Entities/GlobalReplace_Entities.pde b/lib/Regexp/examples/GlobalReplace_Entities/GlobalReplace_Entities.pde new file mode 100644 index 000000000..0122dcc62 --- /dev/null +++ b/lib/Regexp/examples/GlobalReplace_Entities/GlobalReplace_Entities.pde @@ -0,0 +1,45 @@ +#include + +// called for every match +void replace_callback (const char * match, // what we found + const unsigned int length, // how long it was + const char * & replacement, // put replacement here + unsigned int & replacement_length, // put replacement length here + const MatchState & ms) // for looking up captures +{ +static byte c; // for holding replacement byte, must be static + + char hexdigits [3]; // to hold hex string + + // get first capture + ms.GetCapture (hexdigits, 0); + // convert from hex to printable + c = strtol (hexdigits, NULL, 16); + + // set as replacement + replacement = (char *) &c; + replacement_length = 1; +} // end of replace_callback + + +void setup () +{ + Serial.begin (115200); + + // what we are searching + char buf [100] = "%7B%22John+Doe%22%7D"; + + // for matching regular expressions + MatchState ms (buf); + + // easy part, replace + by space + ms.GlobalReplace ("%+", " "); + + // replace %xx (eg. %22) by what the hex code represents + ms.GlobalReplace ("%%(%x%x)", replace_callback); + + Serial.println (buf); + +} // end of setup + +void loop () {} diff --git a/lib/Regexp/examples/Match/Match.pde b/lib/Regexp/examples/Match/Match.pde new file mode 100644 index 000000000..0ede8976c --- /dev/null +++ b/lib/Regexp/examples/Match/Match.pde @@ -0,0 +1,29 @@ +#include + +void setup () +{ + Serial.begin (115200); + + // match state object + MatchState ms; + + // what we are searching (the target) + char buf [100] = "The quick brown fox jumps over the lazy wolf"; + ms.Target (buf); // set its address + Serial.println (buf); + + char result = ms.Match ("f.x"); + + if (result > 0) + { + Serial.print ("Found match at: "); + Serial.println (ms.MatchStart); // 16 in this case + Serial.print ("Match length: "); + Serial.println (ms.MatchLength); // 3 in this case + } + else + Serial.println ("No match."); + +} // end of setup + +void loop () {} diff --git a/lib/Regexp/examples/MatchCount/MatchCount.pde b/lib/Regexp/examples/MatchCount/MatchCount.pde new file mode 100644 index 000000000..553a2ee72 --- /dev/null +++ b/lib/Regexp/examples/MatchCount/MatchCount.pde @@ -0,0 +1,23 @@ +#include + +void setup () +{ + Serial.begin (115200); + + // match state object + MatchState ms; + + // what we are searching (the target) + char buf [100] = "The quick brown fox jumps over the lazy wolf"; + ms.Target (buf); // set its address + + unsigned int count = ms.MatchCount ("[aeiou]"); + + Serial.println (buf); + Serial.print ("Found "); + Serial.print (count); // 11 in this case + Serial.println (" matches."); + +} // end of setup + +void loop () {} diff --git a/lib/Regexp/keywords.txt b/lib/Regexp/keywords.txt new file mode 100644 index 000000000..27950a0f1 --- /dev/null +++ b/lib/Regexp/keywords.txt @@ -0,0 +1,9 @@ +MatchState KEYWORD1 +Match KEYWORD2 +Target KEYWORD2 +GetMatch KEYWORD2 +GetCapture KEYWORD2 +GetResult KEYWORD2 +MatchCount KEYWORD2 +GlobalMatch KEYWORD2 +GlobalReplace KEYWORD2 diff --git a/lib/Regexp/library.properties b/lib/Regexp/library.properties new file mode 100644 index 000000000..a4c7a89f1 --- /dev/null +++ b/lib/Regexp/library.properties @@ -0,0 +1,9 @@ +name=Regexp +version=0.1.0 +author=Nick Gammon +maintainer=Nick Gammon +sentence=Regular expression parser for microcontrollers +paragraph=Based upon Lua implementation +category=Uncategorized +url=https://github.com/nickgammon/Regexp +architectures=* diff --git a/lib/Regexp/src/Regexp.cpp b/lib/Regexp/src/Regexp.cpp new file mode 100644 index 000000000..8fcfa72e7 --- /dev/null +++ b/lib/Regexp/src/Regexp.cpp @@ -0,0 +1,732 @@ +/* + +Regular-expression matching library for Arduino. + +Written by Nick Gammon. +Date: 30 April 2011 + +Heavily based on the Lua regular expression matching library written by Roberto Ierusalimschy. + +Adapted to run on the Arduino by Nick Gammon. + +VERSION + + Version 1.0 - 30th April 2011 : initial release. + Version 1.1 - 1st May 2011 : added some helper functions, made more modular. + Version 1.2 - 19th May 2011 : added more helper functions for replacing etc. + + +LICENSE + + +Copyright © 1994–2010 Lua.org, PUC-Rio. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE + OR OTHER DEALINGS IN THE SOFTWARE. + + +USAGE + + + Find the first match of the regular expression "pattern" in the supplied string, starting at position "index". + + If found, returns REGEXP_MATCHED (1). + + Also match_start and match_len in the MatchState structure are set to the start offset and length of the match. + + The capture in the MatchState structure has the locations and lengths of each capture. + + If not found, returns REGEXP_NOMATCH (0). + + On a parsing error (eg. trailing % symbol) returns a negative number. + + +EXAMPLE OF CALLING ON THE ARDUINO + +// ------------------------------------- // + +#include + +void setup () +{ + + Serial.begin (115200); + Serial.println (); + + MatchState ms; + char buf [100]; // large enough to hold expected string, or malloc it + + // string we are searching + ms.Target ("Testing: answer=42"); + + // search it + char result = ms.Match ("(%a+)=(%d+)", 0); + + // check results + + switch (result) + { + case REGEXP_MATCHED: + + Serial.println ("-----"); + Serial.print ("Matched on: "); + Serial.println (ms.GetMatch (buf)); + + // matching offsets in ms.capture + + Serial.print ("Captures: "); + Serial.println (ms.level); + + for (int j = 0; j < ms.level; j++) + { + Serial.print ("Capture number: "); + Serial.println (j + 1, DEC); + Serial.print ("Text: '"); + Serial.print (ms.GetCapture (buf, j)); + Serial.println ("'"); + + } + break; + + case REGEXP_NOMATCH: + Serial.println ("No match."); + break; + + default: + Serial.print ("Regexp error: "); + Serial.println (result, DEC); + break; + + } // end of switch + +} // end of setup + +void loop () {} // end of loop + +// ------------------------------------- // + + +PATTERNS + + Patterns + + The standard patterns (character classes) you can search for are: + + + . --- (a dot) represents all characters. + %a --- all letters. + %c --- all control characters. + %d --- all digits. + %l --- all lowercase letters. + %p --- all punctuation characters. + %s --- all space characters. + %u --- all uppercase letters. + %w --- all alphanumeric characters. + %x --- all hexadecimal digits. + %z --- the character with hex representation 0x00 (null). + %% --- a single '%' character. + + %1 --- captured pattern 1. + %2 --- captured pattern 2 (and so on). + %f[s] transition from not in set 's' to in set 's'. + %b() balanced pair ( ... ) + + + Important! - the uppercase versions of the above represent the complement of the class. + eg. %U represents everything except uppercase letters, %D represents everything except digits. + + There are some "magic characters" (such as %) that have special meanings. These are: + + + ^ $ ( ) % . [ ] * + - ? + + + If you want to use those in a pattern (as themselves) you must precede them by a % symbol. + + eg. %% would match a single % + + You can build your own pattern classes (sets) by using square brackets, eg. + + + [abc] ---> matches a, b or c + [a-z] ---> matches lowercase letters (same as %l) + [^abc] ---> matches anything except a, b or c + [%a%d] ---> matches all letters and digits + + [%a%d_] ---> matches all letters, digits and underscore + [%[%]] ---> matches square brackets (had to escape them with %) + + + You can use pattern classes in the form %x in the set. + If you use other characters (like periods and brackets, etc.) they are simply themselves. + + You can specify a range of character inside a set by using simple characters (not pattern classes like %a) separated by a hyphen. + For example, [A-Z] or [0-9]. These can be combined with other things. For example [A-Z0-9] or [A-Z,.]. + + A end-points of a range must be given in ascending order. That is, [A-Z] would match upper-case letters, but [Z-A] would not match anything. + + You can negate a set by starting it with a "^" symbol, thus [^0-9] is everything except the digits 0 to 9. + The negation applies to the whole set, so [^%a%d] would match anything except letters or digits. + In anywhere except the first position of a set, the "^" symbol is simply itself. + + Inside a set (that is a sequence delimited by square brackets) the only "magic" characters are: + + ] ---> to end the set, unless preceded by % + % ---> to introduce a character class (like %a), or magic character (like "]") + ^ ---> in the first position only, to negate the set (eg. [^A-Z) + - ---> between two characters, to specify a range (eg. [A-F]) + + + Thus, inside a set, characters like "." and "?" are just themselves. + + The repetition characters, which can follow a character, class or set, are: + + + + ---> 1 or more repetitions (greedy) + * ---> 0 or more repetitions (greedy) + + - ---> 0 or more repetitions (non greedy) + ? ---> 0 or 1 repetition only + + + A "greedy" match will match on as many characters as possible, a non-greedy one will match on as few as possible. + + The standard "anchor" characters apply: + + + ^ ---> anchor to start of subject string + $ ---> anchor to end of subject string + + + You can also use round brackets to specify "captures": + + + You see (.*) here + + + Here, whatever matches (.*) becomes the first pattern. + + You can also refer to matched substrings (captures) later on in an expression: + + eg. This would match: + + string = "You see dogs and dogs" + regexp = "You see (.*) and %1" + + + This example shows how you can look for a repetition of a word matched earlier, whatever that word was ("dogs" in this case). + + As a special case, an empty capture string returns as the captured pattern, the position of itself in the string. eg. + + string = "You see dogs and dogs" + regexp = "You .* ()dogs .*" + + This would return a capture with an offset of 8, and a length of CAP_POSITION (-2) + + Finally you can look for nested "balanced" things (such as parentheses) by using %b, like this: + + + string = "I see a (big fish (swimming) in the pond) here" + regexp = "%b()" + + + After %b you put 2 characters, which indicate the start and end of the balanced pair. + If it finds a nested version it keeps processing until we are back at the top level. + In this case the matching string was "(big fish (swimming) in the pond)". + + +*/ + + +#include +#include +#include +#include "Regexp.h" + +// for throwing errors +static jmp_buf regexp_error_return; +typedef unsigned char byte; + +// error codes raised during regexp processing +static byte error (const char err) +{ + // does not return + longjmp (regexp_error_return, err); + return 0; // keep compiler happy +} // end of error + +static int check_capture (MatchState *ms, int l) { + l -= '1'; + if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) + return error(ERR_INVALID_CAPTURE_INDEX); + return l; +} // end of check_capture + +static int capture_to_close (MatchState *ms) { + int level = ms->level; + for (level--; level>=0; level--) + if (ms->capture[level].len == CAP_UNFINISHED) return level; + return error(ERR_INVALID_PATTERN_CAPTURE); +} // end of capture_to_close + +static const char *classend (MatchState *ms, const char *p) { + switch (*p++) { + case REGEXP_ESC: { + if (*p == '\0') + error(ERR_MALFORMED_PATTERN_ENDS_WITH_ESCAPE); + return p+1; + } + case '[': { + if (*p == '^') p++; + do { /* look for a `]' */ + if (*p == '\0') + error(ERR_MALFORMED_PATTERN_ENDS_WITH_RH_SQUARE_BRACKET); + if (*(p++) == REGEXP_ESC && *p != '\0') + p++; /* skip escapes (e.g. `%]') */ + } while (*p != ']'); + return p+1; + } + default: { + return p; + } + } +} // end of classend + + +static int match_class (int c, int cl) { + int res; + switch (tolower(cl)) { + case 'a' : res = isalpha(c); break; + case 'c' : res = iscntrl(c); break; + case 'd' : res = isdigit(c); break; + case 'l' : res = islower(c); break; + case 'p' : res = ispunct(c); break; + case 's' : res = isspace(c); break; + case 'u' : res = isupper(c); break; + case 'w' : res = isalnum(c); break; + case 'x' : res = isxdigit(c); break; + case 'z' : res = (c == 0); break; + default: return (cl == c); + } + return (islower(cl) ? res : !res); +} // end of match_class + + +static int matchbracketclass (int c, const char *p, const char *ec) { + int sig = 1; + if (*(p+1) == '^') { + sig = 0; + p++; /* skip the `^' */ + } + while (++p < ec) { + if (*p == REGEXP_ESC) { + p++; + if (match_class(c, uchar(*p))) + return sig; + } + else if ((*(p+1) == '-') && (p+2 < ec)) { + p+=2; + if (uchar(*(p-2)) <= c && c <= uchar(*p)) + return sig; + } + else if (uchar(*p) == c) return sig; + } + return !sig; +} // end of matchbracketclass + + +static int singlematch (int c, const char *p, const char *ep) { + switch (*p) { + case '.': return 1; /* matches any char */ + case REGEXP_ESC: return match_class(c, uchar(*(p+1))); + case '[': return matchbracketclass(c, p, ep-1); + default: return (uchar(*p) == c); + } +} // end of singlematch + + +static const char *match (MatchState *ms, const char *s, const char *p); + + +static const char *matchbalance (MatchState *ms, const char *s, + const char *p) { + if (*p == 0 || *(p+1) == 0) + error(ERR_UNBALANCED_PATTERN); + if (*s != *p) return NULL; + else { + int b = *p; + int e = *(p+1); + int cont = 1; + while (++s < ms->src_end) { + if (*s == e) { + if (--cont == 0) return s+1; + } + else if (*s == b) cont++; + } + } + return NULL; /* string ends out of balance */ +} // end of matchbalance + + +static const char *max_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + int i = 0; /* counts maximum expand for item */ + while ((s+i)src_end && singlematch(uchar(*(s+i)), p, ep)) + i++; + /* keeps trying to match with the maximum repetitions */ + while (i>=0) { + const char *res = match(ms, (s+i), ep+1); + if (res) return res; + i--; /* else didn't match; reduce 1 repetition to try again */ + } + return NULL; +} // end of max_expand + + +static const char *min_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + for (;;) { + const char *res = match(ms, s, ep+1); + if (res != NULL) + return res; + else if (ssrc_end && singlematch(uchar(*s), p, ep)) + s++; /* try with one more repetition */ + else return NULL; + } +} // end of min_expand + + +static const char *start_capture (MatchState *ms, const char *s, + const char *p, int what) { + const char *res; + int level = ms->level; + if (level >= MAXCAPTURES) error(ERR_TOO_MANY_CAPTURES); + ms->capture[level].init = s; + ms->capture[level].len = what; + ms->level = level+1; + if ((res=match(ms, s, p)) == NULL) /* match failed? */ + ms->level--; /* undo capture */ + return res; +} // end of start_capture + + +static const char *end_capture (MatchState *ms, const char *s, + const char *p) { + int l = capture_to_close(ms); + const char *res; + ms->capture[l].len = s - ms->capture[l].init; /* close capture */ + if ((res = match(ms, s, p)) == NULL) /* match failed? */ + ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ + return res; +} // end of end_capture + + +static const char *match_capture (MatchState *ms, const char *s, int l) { + size_t len; + l = check_capture(ms, l); + len = ms->capture[l].len; + if ((size_t)(ms->src_end-s) >= len && + memcmp(ms->capture[l].init, s, len) == 0) + return s+len; + else return NULL; +} // end of match_capture + + +static const char *match (MatchState *ms, const char *s, const char *p) { +init: /* using goto's to optimize tail recursion */ + switch (*p) { + case '(': { /* start capture */ + if (*(p+1) == ')') /* position capture? */ + return start_capture(ms, s, p+2, CAP_POSITION); + else + return start_capture(ms, s, p+1, CAP_UNFINISHED); + } + case ')': { /* end capture */ + return end_capture(ms, s, p+1); + } + case REGEXP_ESC: { + switch (*(p+1)) { + case 'b': { /* balanced string? */ + s = matchbalance(ms, s, p+2); + if (s == NULL) return NULL; + p+=4; goto init; /* else return match(ms, s, p+4); */ + } + case 'f': { /* frontier? */ + const char *ep; char previous; + p += 2; + if (*p != '[') + error(ERR_MISSING_LH_SQUARE_BRACKET_AFTER_ESC_F); + ep = classend(ms, p); /* points to what is next */ + previous = (s == ms->src) ? '\0' : *(s-1); + if (matchbracketclass(uchar(previous), p, ep-1) || + !matchbracketclass(uchar(*s), p, ep-1)) return NULL; + p=ep; goto init; /* else return match(ms, s, ep); */ + } + default: { + if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ + s = match_capture(ms, s, uchar(*(p+1))); + if (s == NULL) return NULL; + p+=2; goto init; /* else return match(ms, s, p+2) */ + } + goto dflt; /* case default */ + } + } + } + case '\0': { /* end of pattern */ + return s; /* match succeeded */ + } + case '$': { + if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ + return (s == ms->src_end) ? s : NULL; /* check end of string */ + else goto dflt; + } + default: dflt: { /* it is a pattern item */ + const char *ep = classend(ms, p); /* points to what is next */ + int m = ssrc_end && singlematch(uchar(*s), p, ep); + switch (*ep) { + case '?': { /* optional */ + const char *res; + if (m && ((res=match(ms, s+1, ep+1)) != NULL)) + return res; + p=ep+1; goto init; /* else return match(ms, s, ep+1); */ + } + case '*': { /* 0 or more repetitions */ + return max_expand(ms, s, p, ep); + } + case '+': { /* 1 or more repetitions */ + return (m ? max_expand(ms, s+1, p, ep) : NULL); + } + case '-': { /* 0 or more repetitions (minimum) */ + return min_expand(ms, s, p, ep); + } + default: { + if (!m) return NULL; + s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ + } + } + } + } +} // end of match + + +// functions below written by Nick Gammon ... + +char MatchState::Match (const char * pattern, unsigned int index) +{ + // set up for throwing errors + char rtn = setjmp (regexp_error_return); + + // error return + if (rtn) + return ((result = rtn)); + + if (!src) + error (ERR_NO_TARGET_STRING); + + if (index > src_len) + index = src_len; + + int anchor = (*pattern == '^') ? (pattern++, 1) : 0; + const char *s1 =src + index; + src_end = src + src_len; + + // iterate through target string, character by character unless anchored + do { + const char *res; + level = 0; + if ((res=match(this, s1, pattern)) != NULL) + { + MatchStart = s1 - src; + MatchLength = res - s1; + return (result = REGEXP_MATCHED); + } // end of match at this position + } while (s1++ < src_end && !anchor); + + return (result = REGEXP_NOMATCH); // no match + +} // end of regexp + +// set up the target string +void MatchState::Target (char * s) + { + Target (s, strlen (s)); + } // end of MatchState::Target + +void MatchState::Target (char * s, const unsigned int len) + { + src = s; + src_len = len; + result = REGEXP_NOMATCH; + } // end of MatchState::Target + +// copy the match string to user-supplied buffer +// buffer must be large enough to hold it +char * MatchState::GetMatch (char * s) const +{ + if (result != REGEXP_MATCHED) + s [0] = 0; + else + { + memcpy (s, &src [MatchStart], MatchLength); + s [MatchLength] = 0; // null-terminated string + } + return s; +} // end of MatchState::GetMatch + +// get one of the capture strings (zero-relative level) +// buffer must be large enough to hold it +char * MatchState::GetCapture (char * s, const int n) const +{ + if (result != REGEXP_MATCHED || n >= level || capture [n].len <= 0) + s [0] = 0; + else + { + memcpy (s, capture [n].init, capture [n].len); + s [capture [n].len] = 0; // null-terminated string + } + return s; +} // end of MatchState::GetCapture + +// match repeatedly on a string, return count of matches +unsigned int MatchState::MatchCount (const char * pattern) +{ + unsigned int count = 0; + + // keep matching until we run out of matches + for (unsigned int index = 0; + Match (pattern, index) > 0 && + index < src_len; // otherwise empty matches loop + count++) + // increment index ready for next time, go forwards at least one byte + index = MatchStart + (MatchLength == 0 ? 1 : MatchLength); + + return count; + +} // end of MatchState::MatchCount + +// match repeatedly on a string, call function f for each match +unsigned int MatchState::GlobalMatch (const char * pattern, GlobalMatchCallback f) +{ + unsigned int count = 0; + + // keep matching until we run out of matches + for (unsigned int index = 0; + Match (pattern, index) > 0; + count++) + { + f (& src [MatchStart], MatchLength, *this); + // increment index ready for next time, go forwards at least one byte + index = MatchStart + (MatchLength == 0 ? 1 : MatchLength); + } // end of for each match + return count; + +} // end of MatchState::GlobalMatch + +// match repeatedly on a string, call function f for each match +// f sets replacement string, incorporate replacement and continue +// maximum of max_count replacements if max_count > 0 +// replacement string in GlobalReplaceCallback must stay in scope (eg. static string or literal) +unsigned int MatchState::GlobalReplace (const char * pattern, GlobalReplaceCallback f, const unsigned int max_count) +{ + unsigned int count = 0; + + // keep matching until we run out of matches + for (unsigned int index = 0; + Match (pattern, index) > 0 && // stop when no match + index < src_len && // otherwise empty matches loop + (max_count == 0 || count < max_count); // stop when count reached + count++) + { + // default is to replace with self + const char * replacement = &src [MatchStart]; + unsigned int replacement_length = MatchLength; + + // increment index ready for next time, go forwards at least one byte + if (MatchLength == 0) + index = MatchStart + 1; // go forwards at least one byte or we will loop forever + else + { + // increment index ready for next time, + index = MatchStart + MatchLength; + + // call function to find replacement text + f (&src [MatchStart], MatchLength, replacement, replacement_length, *this); + + // see how much memory we need to move + int lengthDiff = MatchLength - replacement_length; + + // copy the rest of the buffer backwards/forwards to allow for the length difference + memmove (&src [index - lengthDiff], &src [index], src_len - index); + + // copy in the replacement + memmove (&src [MatchStart], replacement, replacement_length); + + // adjust the index for the next search + index -= lengthDiff; + // and the length of the source + src_len -= lengthDiff; + } // end if matching at least one byte + } // end of for each match + + // put a terminating null in + src [src_len] = 0; + return count; +} // end of MatchState::GlobalReplace + + +// match repeatedly on a string, replaces with replacement string for each match +// maximum of max_count replacements if max_count > 0 +// replacement string in GlobalReplaceCallback must stay in scope (eg. static string or literal) +unsigned int MatchState::GlobalReplace (const char * pattern, const char * replacement, const unsigned int max_count) +{ + unsigned int count = 0; + unsigned int replacement_length = strlen (replacement); + + // keep matching until we run out of matches + for (unsigned int index = 0; + Match (pattern, index) > 0 && // stop when no match + index < src_len && // otherwise empty matches loop + (max_count == 0 || count < max_count); // stop when count reached + count++) + { + if (MatchLength == 0) + index = MatchStart + 1; // go forwards at least one byte or we will loop forever + else + { + // increment index ready for next time, + index = MatchStart + MatchLength; + + // see how much memory we need to move + int lengthDiff = MatchLength - replacement_length; + + // copy the rest of the buffer backwards/forwards to allow for the length difference + memmove (&src [index - lengthDiff], &src [index], src_len - index); + + // copy in the replacement + memmove (&src [MatchStart], replacement, replacement_length); + + // adjust the index for the next search + index -= lengthDiff; + // and the length of the source + src_len -= lengthDiff; + } // end if matching at least one byte + + } // end of for each match + + // put a terminating null in + src [src_len] = 0; + return count; +} // end of MatchState::GlobalReplace + diff --git a/lib/Regexp/src/Regexp.h b/lib/Regexp/src/Regexp.h new file mode 100644 index 000000000..a929b335a --- /dev/null +++ b/lib/Regexp/src/Regexp.h @@ -0,0 +1,131 @@ +/* + + Regular-expression matching library for Arduino. + + Written by Nick Gammon. + Date: 30 April 2011 + + Heavily based on the Lua regular expression matching library written by Roberto Ierusalimschy. + + Adapted to run on the Arduino by Nick Gammon. + + + VERSION + + Version 1.0 - 30th April 2011 : initial release. + Version 1.1 - 1st May 2011 : added some helper functions, made more modular. + Version 1.2 - 19th May 2011 : added more helper functions for replacing etc. + + + */ + +#pragma once + + +// Maximum of captures we can return. +// Increase if you need more, decrease to save memory. +#define MAXCAPTURES 32 + +// the "magic escape" character +#define REGEXP_ESC '%' + +// special characters that have to be escaped +// (not used in the library, but you might need this) +#define REGEXP_SPECIALS "^$*+?.([%-" + +// Result codes from calling regexp: + +// we got a match +#define REGEXP_MATCHED 1 + +// no match, or not attempted to match yet +#define REGEXP_NOMATCH 0 + +// errors when matching +#define ERR_INVALID_CAPTURE_INDEX -1 +#define ERR_INVALID_PATTERN_CAPTURE -2 +#define ERR_MALFORMED_PATTERN_ENDS_WITH_ESCAPE -3 +#define ERR_MALFORMED_PATTERN_ENDS_WITH_RH_SQUARE_BRACKET -4 +#define ERR_UNBALANCED_PATTERN -5 +#define ERR_TOO_MANY_CAPTURES -6 +#define ERR_MISSING_LH_SQUARE_BRACKET_AFTER_ESC_F -7 +#define ERR_NO_TARGET_STRING -8 + + +/* macro to `unsign' a character */ +#define uchar(c) ((unsigned char)(c)) + +// special capture "lengths" +#define CAP_UNFINISHED (-1) +#define CAP_POSITION (-2) + +class MatchState; // forward definition for the callback routines + +typedef void (*GlobalMatchCallback) (const char * match, // matching string (not null-terminated) + const unsigned int length, // length of matching string + const MatchState & ms); // MatchState in use (to get captures) +typedef void (*GlobalReplaceCallback) (const char * match, // matching string (not null-terminated) + const unsigned int length, // length of matching string + const char * & replacement, + unsigned int & replacement_length, + const MatchState & ms); // MatchState in use (to get captures) +typedef class MatchState { +private: + + char result; // result of last Match call + +public: + + MatchState () : result (REGEXP_NOMATCH), src (0) {}; // constructor + MatchState (char * s) : result (REGEXP_NOMATCH) + { Target (s); }; // constructor from null-terminated string + MatchState (char * s, const unsigned int len) : result (REGEXP_NOMATCH) + { Target (s, len); }; // constructor from string and length + + // supply these two: + char *src = nullptr; /* source string */ + unsigned int src_len = 0; /* length of source string */ + + // used internally + char *src_end = nullptr; /* end of source string */ + + // returned fields: + + unsigned int MatchStart = 0; // zero-relative offset of start of match + unsigned int MatchLength = 0; // length of match + + int level; /* total number of captures in array below (finished or unfinished) */ + + // capture addresses and lengths + struct { + const char *init; + int len; // might be CAP_UNFINISHED or CAP_POSITION + } capture[MAXCAPTURES]; + + // add target string, null-terminated + void Target (char * s); + // add target string, with specified length + void Target (char * s, const unsigned int len); + // do a match on a supplied pattern and zero-relative starting point + char Match (const char * pattern, unsigned int index = 0); + // return the matching string + char * GetMatch (char * s) const; + // return capture string n + char * GetCapture (char * s, const int n) const; + // get result of previous match + char GetResult () const { return result; } + + // count number of matches on a supplied pattern + unsigned int MatchCount (const char * pattern); + // iterate with a supplied pattern, call function f for each match + // returns count of matches + unsigned int GlobalMatch (const char * pattern, GlobalMatchCallback f); + // iterate with a supplied pattern, call function f for each match, maximum of max_count matches if max_count > 0 + // returns count of replacements + unsigned int GlobalReplace (const char * pattern, GlobalReplaceCallback f, const unsigned int max_count = 0); + // iterate with a supplied pattern, replaces with replacement string, maximum of max_count matches if max_count > 0 + // returns count of replacements + unsigned int GlobalReplace (const char * pattern, const char * replacement, const unsigned int max_count = 0); + +} MatchState; + From ce6e151cb21b695a237b4d12c49e87e8170b340e Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 12 Mar 2020 00:23:55 +0100 Subject: [PATCH 19/40] [Serial Proxy] Add regexp filtering using captures --- src/WebServer_Markup.ino | 42 ++++++++++++--- src/_P087_SerialProxy.ino | 110 ++++++++++++++++++++++++++++++-------- 2 files changed, 122 insertions(+), 30 deletions(-) diff --git a/src/WebServer_Markup.ino b/src/WebServer_Markup.ino index 9c1efc929..6fadffbf2 100644 --- a/src/WebServer_Markup.ino +++ b/src/WebServer_Markup.ino @@ -10,9 +10,22 @@ void addSelector(const String& id, int selectedIndex, boolean reloadonchange, bool enabled) +{ + addSelector(id, optionCount, options, indices, attr, selectedIndex, reloadonchange, enabled, F("wide")); +} + +void addSelector(const String& id, + int optionCount, + const String options[], + const int indices[], + const String attr[], + int selectedIndex, + boolean reloadonchange, + bool enabled, + const String& classname) { // FIXME TD-er Change boolean to disabled - addSelector_Head(id, reloadonchange, !enabled); + addSelector_Head(id, classname, reloadonchange, !enabled); addSelector_options(optionCount, options, indices, attr, selectedIndex); addSelector_Foot(); } @@ -51,24 +64,30 @@ void addSelector_options(int optionCount, const String options[], const int indi } void addSelector_Head(const String& id, boolean reloadonchange) { - addSelector_Head(id, reloadonchange, false); + addSelector_Head(id, F("wide"), reloadonchange); } -void addSelector_Head(const String& id, boolean reloadonchange, bool disabled) +void addSelector_Head(const String& id, const String& classname, boolean reloadonchange) { + addSelector_Head(id, classname, reloadonchange, false); +} + +void addSelector_Head(const String& id, const String& classname, boolean reloadonchange, bool disabled) { if (reloadonchange) { - addSelector_Head(id, (const String)F("return dept_onchange(frmselect)"), disabled); + addSelector_Head(id, classname, (const String)F("return dept_onchange(frmselect)"), disabled); } else { - addSelector_Head(id, (const String)"", disabled); + addSelector_Head(id, classname, (const String)"", disabled); } } -void addSelector_Head(const String& id, const String& onChangeCall, bool disabled) +void addSelector_Head(const String& id, const String& onChangeCall, const String& classname, bool disabled) { { String html; html.reserve(32 + id.length()); - html += F(""); - html_TD(); + html_TR_TD(); addSubmitButton(); addHelpButton(F("ESPEasy_Command_Reference")); html_TR_TD(); From a3be53b8b1eb9c05114cc8520ee6a611f2e4f76e Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 14 Mar 2020 14:03:57 +0100 Subject: [PATCH 24/40] [Serial Proxy] Only check on valid filter rules --- src/_P087_SerialProxy.ino | 19 +++---- src/src/PluginStructs/P087_data_struct.cpp | 59 +++++++++++++++++----- src/src/PluginStructs/P087_data_struct.h | 11 ++-- 3 files changed, 61 insertions(+), 28 deletions(-) diff --git a/src/_P087_SerialProxy.ino b/src/_P087_SerialProxy.ino index 90e62dca9..ae419ca8e 100644 --- a/src/_P087_SerialProxy.ino +++ b/src/_P087_SerialProxy.ino @@ -302,19 +302,16 @@ void P087_html_show_matchForms(struct EventStruct *event) { addFormNote(F("0 = Do not turn off filter after sending to the connected device.")); { - String options[4]; - options[P087_Match_Type::Regular_Match] = F("Regular Match"); - options[P087_Match_Type::Regular_Match_inverted] = F("Regular Match inverted"); - options[P087_Match_Type::Global_Match] = F("Global Match"); - options[P087_Match_Type::Global_Match_inverted] = F("Global Match inverted"); - - int optionValues[4] = { P087_Match_Type::Regular_Match, - P087_Match_Type::Regular_Match_inverted, - P087_Match_Type::Global_Match, - P087_Match_Type::Global_Match_inverted }; + String options[P087_Match_Type_NR_ELEMENTS]; + int optionValues[P087_Match_Type_NR_ELEMENTS]; + for (int i = 0; i < P087_Match_Type_NR_ELEMENTS; ++i) { + P087_Match_Type matchType = static_cast(i); + options[i] = P087_data_struct::MatchType_toString(matchType); + optionValues[i] = matchType; + } P087_Match_Type choice = P087_data->getMatchType(); - addFormSelector(F("Match Type"), getPluginCustomArgName(P087_MATCH_TYPE_POS), 4, options, optionValues, choice, false); + addFormSelector(F("Match Type"), getPluginCustomArgName(P087_MATCH_TYPE_POS), P087_Match_Type_NR_ELEMENTS, options, optionValues, choice, false); addFormNote(F("Capture filter can only be used on Global Match")); } diff --git a/src/src/PluginStructs/P087_data_struct.cpp b/src/src/PluginStructs/P087_data_struct.cpp index d342771a7..e1a0ce8cc 100644 --- a/src/src/PluginStructs/P087_data_struct.cpp +++ b/src/src/PluginStructs/P087_data_struct.cpp @@ -36,17 +36,19 @@ void P087_data_struct::post_init() { capture_index_used[i] = false; } String log = F("P087_post_init:"); + for (uint8_t i = 0; i < P087_NR_FILTERS; ++i) { // Create some quick lookup table to see if we have a filter for the specific index capture_index_must_not_match[i] = _lines[i * 3 + P087_FIRST_FILTER_POS + 1].toInt() == P087_Filter_Comp::NotEqual; int index = _lines[i * 3 + P087_FIRST_FILTER_POS].toInt(); + // Index is negative when not used. - if (index >= 0 && index < P87_MAX_CAPTURE_INDEX && _lines[i * 3 + P087_FIRST_FILTER_POS + 1].length() > 0) { - log += ' '; - log += String(i); - log += ':'; - log += String(index); - capture_index[i] = index; + if ((index >= 0) && (index < P87_MAX_CAPTURE_INDEX) && (_lines[i * 3 + P087_FIRST_FILTER_POS + 1].length() > 0)) { + log += ' '; + log += String(i); + log += ':'; + log += String(index); + capture_index[i] = index; capture_index_used[index] = true; } } @@ -175,6 +177,8 @@ bool P087_data_struct::invertMatch() const { case Regular_Match_inverted: // fallthrough case Global_Match_inverted: return true; + case Filter_Disabled: + break; } return false; } @@ -187,6 +191,8 @@ bool P087_data_struct::globalMatch() const { case Global_Match: // fallthrough case Global_Match_inverted: return true; + case Filter_Disabled: + break; } return false; } @@ -221,7 +227,6 @@ bool P087_data_struct::disableFilterWindowActive() const { return false; } - typedef std::pair capture_tuple; static std::vector capture_vector; @@ -232,7 +237,7 @@ void P087_data_struct::match_callback(const char *match, const unsigned int leng for (byte i = 0; i < ms.level; i++) { capture_tuple tuple; - tuple.first = 1; + tuple.first = 1; tuple.second = ms.GetCapture(i); capture_vector.push_back(tuple); } // end of for each capture @@ -257,23 +262,30 @@ bool P087_data_struct::matchRegexp(String& received) const { bool match_result = false; - if (globalMatch()) { + if (getMatchType() == Filter_Disabled) { + match_result = true; + } else if (globalMatch()) { capture_vector.clear(); ms.GlobalMatch(_lines[P087_REGEX_POS].c_str(), match_callback); const uint8_t vectorlength = capture_vector.size(); + for (uint8_t i = 0; i < vectorlength; ++i) { - if (capture_vector[i].first < P87_MAX_CAPTURE_INDEX && capture_index_used[capture_vector[i].first]) { + if ((capture_vector[i].first < P87_MAX_CAPTURE_INDEX) && capture_index_used[capture_vector[i].first]) { for (uint8_t n = 0; n < P087_NR_FILTERS; ++n) { - if (capture_index[n] == capture_vector[i].first) { + unsigned int lines_index = n * 3 + P087_FIRST_FILTER_POS + 2; + + if ((capture_index[n] == capture_vector[i].first) && (_lines[lines_index].length() != 0)) { String log; log.reserve(32); - log = F("P087: Index: "); + log = F("P087: Index: "); log += capture_vector[i].first; log += F(" Found "); log += capture_vector[i].second; + // Found a Capture Filter with this capture index. - if (capture_vector[i].second == _lines[n * 3 + P087_FIRST_FILTER_POS + 2]) { + if (capture_vector[i].second == _lines[lines_index]) { log += F(" Matches"); + // Found a match. Now check if it is supposed to be one or not. if (capture_index_must_not_match[n]) { log += F(" (!=)"); @@ -281,10 +293,17 @@ bool P087_data_struct::matchRegexp(String& received) const { return false; } else { match_result = true; - log += F(" (==)"); + log += F(" (==)"); } } else { log += F(" No Match"); + + if (capture_index_must_not_match[n]) { + log += F(" (!=) "); + } else { + log += F(" (==) "); + } + log += _lines[lines_index]; } addLog(LOG_LEVEL_INFO, log); } @@ -309,6 +328,18 @@ bool P087_data_struct::matchRegexp(String& received) const { return match_result; } +String P087_data_struct::MatchType_toString(P087_Match_Type matchType) { + switch (matchType) + { + case P087_Match_Type::Regular_Match: return F("Regular Match"); + case P087_Match_Type::Regular_Match_inverted: return F("Regular Match inverted"); + case P087_Match_Type::Global_Match: return F("Global Match"); + case P087_Match_Type::Global_Match_inverted: return F("Global Match inverted"); + case P087_Match_Type::Filter_Disabled: return F("Filter Disabled"); + } + return ""; +} + bool P087_data_struct::max_length_reached() const { if (max_length == 0) { return false; } return sentence_part.length() >= max_length; diff --git a/src/src/PluginStructs/P087_data_struct.h b/src/src/PluginStructs/P087_data_struct.h index df4e38066..8cd58d7d0 100644 --- a/src/src/PluginStructs/P087_data_struct.h +++ b/src/src/PluginStructs/P087_data_struct.h @@ -30,8 +30,11 @@ enum P087_Match_Type { Regular_Match = 0, Regular_Match_inverted = 1, Global_Match = 2, - Global_Match_inverted = 3 + Global_Match_inverted = 3, + Filter_Disabled = 4 }; +# define P087_Match_Type_NR_ELEMENTS 5 + struct P087_data_struct : public PluginTaskData_base { public: @@ -92,7 +95,9 @@ public: const unsigned int length, const MatchState & ms); - bool matchRegexp(String& received) const; + bool matchRegexp(String& received) const; + + static String MatchType_toString(P087_Match_Type matchType); // Made public so we don't have to copy the values when loading/saving. @@ -110,7 +115,7 @@ private: uint32_t length_last_received = 0; unsigned long disable_filter_window = 0; - uint8_t capture_index[P87_MAX_CAPTURE_INDEX] = {0}; + uint8_t capture_index[P87_MAX_CAPTURE_INDEX] = { 0 }; bool capture_index_used[P87_MAX_CAPTURE_INDEX]; bool capture_index_must_not_match[P87_MAX_CAPTURE_INDEX]; From c5c22643c62f725c22d80e55d3360885cf017baa Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 14 Mar 2020 20:37:42 +0100 Subject: [PATCH 25/40] [SysVar] Add extra system variables to get build info Added: - `%sysbuild_desc%` - `%sysbuild_filename%` - `%sysbuild_git%` --- src/WebServer_SysVarPage.ino | 89 +++++++++++++--------- src/src/Helpers/SystemVariables.cpp | 59 ++++++++------ src/src/Helpers/SystemVariables.h | 3 + src/src/PluginStructs/P087_data_struct.cpp | 2 +- 4 files changed, 92 insertions(+), 61 deletions(-) diff --git a/src/WebServer_SysVarPage.ino b/src/WebServer_SysVarPage.ino index 3cedb63d6..336277046 100644 --- a/src/WebServer_SysVarPage.ino +++ b/src/WebServer_SysVarPage.ino @@ -1,9 +1,17 @@ #ifdef WEBSERVER_SYSVARS + +#include "src/Helpers/SystemVariables.h" + // ******************************************************************************** // Web Interface sysvars showing all system vars and their value. // ******************************************************************************** +void addSysVar_enum_html(SystemVariables::Enum enumval) { + addSysVar_html(SystemVariables::toString(enumval)); +} + + void handle_sysvars() { checkRAM(F("handle_sysvars")); @@ -23,52 +31,56 @@ void handle_sysvars() { html_table_header(F("URL encoded"), F("ESPEasy_System_Variables"), 0); addTableSeparator(F("Constants"), 3, 3); - addSysVar_html(F("%CR%")); - addSysVar_html(F("%LF%")); - addSysVar_html(F("%SP%")); - addSysVar_html(F("%R%")); - addSysVar_html(F("%N%")); + addSysVar_enum_html(SystemVariables::CR); + addSysVar_enum_html(SystemVariables::LF); + addSysVar_enum_html(SystemVariables::SPACE); + addSysVar_enum_html(SystemVariables::S_CR); + addSysVar_enum_html(SystemVariables::S_LF); addTableSeparator(F("Network"), 3, 3); - addSysVar_html(F("%mac%")); + addSysVar_enum_html(SystemVariables::MAC); #if defined(ESP8266) - addSysVar_html(F("%mac_int%")); + addSysVar_enum_html(SystemVariables::MAC_INT); #endif // if defined(ESP8266) - addSysVar_html(F("%ip4%")); - addSysVar_html(F("%ip%")); - addSysVar_html(F("%rssi%")); - addSysVar_html(F("%ssid%")); - addSysVar_html(F("%bssid%")); - addSysVar_html(F("%wi_ch%")); + addSysVar_enum_html(SystemVariables::IP4); + addSysVar_enum_html(SystemVariables::IP4); + addSysVar_enum_html(SystemVariables::RSSI); + addSysVar_enum_html(SystemVariables::SSID); + addSysVar_enum_html(SystemVariables::BSSID); + addSysVar_enum_html(SystemVariables::WI_CH); addTableSeparator(F("System"), 3, 3); - addSysVar_html(F("%unit%")); - addSysVar_html(F("%sysload%")); - addSysVar_html(F("%sysheap%")); - addSysVar_html(F("%sysstack%")); - addSysVar_html(F("%sysname%")); + addSysVar_enum_html(SystemVariables::UNIT_sysvar); + addSysVar_enum_html(SystemVariables::SYSLOAD); + addSysVar_enum_html(SystemVariables::SYSHEAP); + addSysVar_enum_html(SystemVariables::SYSSTACK); + addSysVar_enum_html(SystemVariables::SYSNAME); #if FEATURE_ADC_VCC - addSysVar_html(F("%vcc%")); + addSysVar_enum_html(SystemVariables::VCC); #endif // if FEATURE_ADC_VCC addTableSeparator(F("System status"), 3, 3); - addSysVar_html(F("%iswifi%")); - addSysVar_html(F("%isntp%")); - addSysVar_html(F("%ismqtt%")); + addSysVar_enum_html(SystemVariables::ISWIFI); + addSysVar_enum_html(SystemVariables::ISNTP); + addSysVar_enum_html(SystemVariables::ISMQTT); #ifdef USES_P037 - addSysVar_html(F("%ismqttimp%")); + addSysVar_enum_html(SystemVariables::ISMQTTIMP); #endif // USES_P037 addTableSeparator(F("Time"), 3, 3); - addSysVar_html(F("%lcltime%")); - addSysVar_html(F("%lcltime_am%")); - addSysVar_html(F("%systm_hm%")); - addSysVar_html(F("%systm_hm_am%")); - addSysVar_html(F("%systime%")); - addSysVar_html(F("%systime_am%")); - addSysVar_html(F("%sysbuild_date%")); - addSysVar_html(F("%sysbuild_time%")); + addSysVar_enum_html(SystemVariables::LCLTIME); + addSysVar_enum_html(SystemVariables::LCLTIME_AM); + addSysVar_enum_html(SystemVariables::SYSTM_HM); + addSysVar_enum_html(SystemVariables::SYSTM_HM_AM); + addSysVar_enum_html(SystemVariables::SYSTIME); + addSysVar_enum_html(SystemVariables::SYSTIME_AM); + addSysVar_enum_html(SystemVariables::SYSBUILD_DATE); + addSysVar_enum_html(SystemVariables::SYSBUILD_TIME); + addSysVar_enum_html(SystemVariables::SYSBUILD_FILENAME); + addSysVar_enum_html(SystemVariables::SYSBUILD_DESCR); + addSysVar_enum_html(SystemVariables::SYSBUILD_GIT); + addTableSeparator(F("System"), 3, 3); addSysVar_html(F("%sysyear% // %sysyear_0%")); addSysVar_html(F("%sysyears%")); @@ -77,14 +89,14 @@ void handle_sysvars() { addSysVar_html(F("%syshour% // %syshour_0%")); addSysVar_html(F("%sysmin% // %sysmin_0%")); addSysVar_html(F("%syssec% // %syssec_0%")); - addSysVar_html(F("%syssec_d%")); - addSysVar_html(F("%sysweekday%")); - addSysVar_html(F("%sysweekday_s%")); + addSysVar_enum_html(SystemVariables::SYSSEC_D); + addSysVar_enum_html(SystemVariables::SYSWEEKDAY); + addSysVar_enum_html(SystemVariables::SYSWEEKDAY_S); addTableSeparator(F("System"), 3, 3); - addSysVar_html(F("%uptime%")); - addSysVar_html(F("%unixtime%")); - addSysVar_html(F("%unixday%")); - addSysVar_html(F("%unixday_sec%")); + addSysVar_enum_html(SystemVariables::UPTIME); + addSysVar_enum_html(SystemVariables::UNIXTIME); + addSysVar_enum_html(SystemVariables::UNIXDAY); + addSysVar_enum_html(SystemVariables::UNIXDAY_SEC); addSysVar_html(F("%sunset%")); addSysVar_html(F("%sunset-1h%")); addSysVar_html(F("%sunrise%")); @@ -172,6 +184,7 @@ void handle_sysvars() { TXBuffer.endStream(); } + void addSysVar_html(const String& input) { html_TR_TD(); { diff --git a/src/src/Helpers/SystemVariables.cpp b/src/src/Helpers/SystemVariables.cpp index ff9984ecc..82898126c 100644 --- a/src/src/Helpers/SystemVariables.cpp +++ b/src/src/Helpers/SystemVariables.cpp @@ -7,8 +7,8 @@ #ifdef USES_MQTT -#include "../Globals/MQTT.h" -#endif +# include "../Globals/MQTT.h" +#endif // ifdef USES_MQTT String getReplacementString(const String& format, String& s) { @@ -63,45 +63,51 @@ void SystemVariables::parseSystemVariables(String& s, boolean useURLencode) } SystemVariables::Enum enumval = static_cast(0); + do { enumval = SystemVariables::nextReplacementEnum(s, enumval); String value; - switch (enumval) + + switch (enumval) { case BSSID: value = String((wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? F("00:00:00:00:00:00") : WiFi.BSSIDstr()); break; case CR: value = "\r"; break; case IP: value = getValue(LabelType::IP_ADDRESS); break; - case IP4: value = WiFi.localIP().toString().substring(WiFi.localIP().toString().lastIndexOf('.') + 1); break; // 4th IP octet + case IP4: value = WiFi.localIP().toString().substring(WiFi.localIP().toString().lastIndexOf('.') + 1); break; // 4th IP + // octet #ifdef USES_MQTT case ISMQTT: value = String(MQTTclient_connected); break; - #else + #else // ifdef USES_MQTT case ISMQTT: value = "0"; break; #endif // ifdef USES_MQTT #ifdef USES_P037 case ISMQTTIMP: value = String(P037_MQTTImport_connected); break; - #else + #else // ifdef USES_P037 case ISMQTTIMP: value = "0"; break; #endif // USES_P037 case ISNTP: value = String(statusNTPInitialized); break; - case ISWIFI: value = String(wifiStatus); break; // 0=disconnected, 1=connected, 2=got ip, 3=services initialized + case ISWIFI: value = String(wifiStatus); break; // 0=disconnected, 1=connected, 2=got ip, 3=services initialized case LCLTIME: value = getValue(LabelType::LOCAL_TIME); break; case LCLTIME_AM: value = node_time.getDateTimeString_ampm('-', ':', ' '); break; case LF: value = "\n"; break; case MAC: value = getValue(LabelType::STA_MAC); break; #ifdef ESP8266 - case MAC_INT: value = String(ESP.getChipId()); break; // Last 24 bit of MAC address as integer, to be used in rules. - #else - case MAC_INT: value = ""; break; // FIXME TD-er: Must find proper altrnative for ESP32. - #endif + case MAC_INT: value = String(ESP.getChipId()); break; // Last 24 bit of MAC address as integer, to be used in rules. + #else // ifdef ESP8266 + case MAC_INT: value = ""; break; // FIXME TD-er: Must find proper altrnative for ESP32. + #endif // ifdef ESP8266 case RSSI: value = getValue(LabelType::WIFI_RSSI); break; case SPACE: value = " "; break; case SSID: value = (wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? F("--") : WiFi.SSID(); break; case SUNRISE: SMART_REPL_T(SystemVariables::toString(enumval), replSunRiseTimeString); break; case SUNSET: SMART_REPL_T(SystemVariables::toString(enumval), replSunSetTimeString); break; case SYSBUILD_DATE: value = String(CRCValues.compileDate); break; + case SYSBUILD_DESCR: value = getValue(LabelType::BUILD_DESC); break; + case SYSBUILD_FILENAME: value = getValue(LabelType::BINARY_FILENAME); break; + case SYSBUILD_GIT: value = getValue(LabelType::GIT_BUILD); break; case SYSBUILD_TIME: value = String(CRCValues.compileTime); break; case SYSDAY: value = String(node_time.day()); break; case SYSDAY_0: value = timeReplacement_leadZero(node_time.day()); break; @@ -136,23 +142,25 @@ void SystemVariables::parseSystemVariables(String& s, boolean useURLencode) case UPTIME: value = String(wdcounter / 2); break; #if FEATURE_ADC_VCC case VCC: value = String(vcc); break; - #else + #else // if FEATURE_ADC_VCC case VCC: value = String(-1); break; #endif // if FEATURE_ADC_VCC case WI_CH: value = String((wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? 0 : WiFi.channel()); break; case UNKNOWN: - break; + break; } - switch(enumval) + switch (enumval) { case SUNRISE: case SUNSET: case UNKNOWN: + // Do not replace break; default: + if (useURLencode) { value = URLEncode(value.c_str()); } @@ -167,6 +175,7 @@ void SystemVariables::parseSystemVariables(String& s, boolean useURLencode) if ((v_index != -1) && isDigit(s[v_index + 2])) { for (byte i = 0; i < CUSTOM_VARS_MAX; ++i) { String key = "%v" + String(i + 1) + '%'; + if (s.indexOf(key) != -1) { String value = String(customFloatVar[i]); @@ -191,23 +200,28 @@ SystemVariables::Enum SystemVariables::nextReplacementEnum(const String& str, Sy } SystemVariables::Enum nextTested = static_cast(0); + if (last_tested > nextTested) { nextTested = static_cast(last_tested + 1); } + if (nextTested >= Enum::UNKNOWN) { return Enum::UNKNOWN; } - String str_prefix = SystemVariables::toString(nextTested).substring(0,2); - bool str_prefix_exists = str.indexOf(str_prefix) != -1; + String str_prefix = SystemVariables::toString(nextTested).substring(0, 2); + bool str_prefix_exists = str.indexOf(str_prefix) != -1; + for (int i = nextTested; i < Enum::UNKNOWN; ++i) { SystemVariables::Enum enumval = static_cast(i); - String new_str_prefix = SystemVariables::toString(enumval).substring(0,2); - if (str_prefix == new_str_prefix && !str_prefix_exists) { + String new_str_prefix = SystemVariables::toString(enumval).substring(0, 2); + + if ((str_prefix == new_str_prefix) && !str_prefix_exists) { // Just continue } else { - str_prefix = new_str_prefix; + str_prefix = new_str_prefix; str_prefix_exists = str.indexOf(str_prefix) != -1; + if (str_prefix_exists) { if (str.indexOf(SystemVariables::toString(enumval)) != -1) { return enumval; @@ -219,8 +233,6 @@ SystemVariables::Enum SystemVariables::nextReplacementEnum(const String& str, Sy return Enum::UNKNOWN; } - - String SystemVariables::toString(SystemVariables::Enum enumval) { switch (enumval) { @@ -243,6 +255,9 @@ String SystemVariables::toString(SystemVariables::Enum enumval) case Enum::SUNRISE: return F("%sunrise"); case Enum::SUNSET: return F("%sunset"); case Enum::SYSBUILD_DATE: return F("%sysbuild_date%"); + case Enum::SYSBUILD_DESCR: return F("%sysbuild_desc%"); + case Enum::SYSBUILD_FILENAME: return F("%sysbuild_filename%"); + case Enum::SYSBUILD_GIT: return F("%sysbuild_git%"); case Enum::SYSBUILD_TIME: return F("%sysbuild_time%"); case Enum::SYSDAY: return F("%sysday%"); case Enum::SYSDAY_0: return F("%sysday_0%"); @@ -280,4 +295,4 @@ String SystemVariables::toString(SystemVariables::Enum enumval) case Enum::UNKNOWN: break; } return F("Unknown"); -} \ No newline at end of file +} diff --git a/src/src/Helpers/SystemVariables.h b/src/src/Helpers/SystemVariables.h index c82ceb918..67421791b 100644 --- a/src/src/Helpers/SystemVariables.h +++ b/src/src/Helpers/SystemVariables.h @@ -28,6 +28,9 @@ public: SUNRISE, SUNSET, SYSBUILD_DATE, + SYSBUILD_DESCR, + SYSBUILD_FILENAME, + SYSBUILD_GIT, SYSBUILD_TIME, SYSDAY, SYSDAY_0, diff --git a/src/src/PluginStructs/P087_data_struct.cpp b/src/src/PluginStructs/P087_data_struct.cpp index e1a0ce8cc..74e4cf82e 100644 --- a/src/src/PluginStructs/P087_data_struct.cpp +++ b/src/src/PluginStructs/P087_data_struct.cpp @@ -237,7 +237,7 @@ void P087_data_struct::match_callback(const char *match, const unsigned int leng for (byte i = 0; i < ms.level; i++) { capture_tuple tuple; - tuple.first = 1; + tuple.first = i; tuple.second = ms.GetCapture(i); capture_vector.push_back(tuple); } // end of for each capture From 812323874e59067865209677366bc76054adf97f Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sun, 15 Mar 2020 01:41:48 +0100 Subject: [PATCH 26/40] [Serial Proxy] Fix check in empty string test --- src/src/PluginStructs/P087_data_struct.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/PluginStructs/P087_data_struct.cpp b/src/src/PluginStructs/P087_data_struct.cpp index 74e4cf82e..2591058ef 100644 --- a/src/src/PluginStructs/P087_data_struct.cpp +++ b/src/src/PluginStructs/P087_data_struct.cpp @@ -43,7 +43,7 @@ void P087_data_struct::post_init() { int index = _lines[i * 3 + P087_FIRST_FILTER_POS].toInt(); // Index is negative when not used. - if ((index >= 0) && (index < P87_MAX_CAPTURE_INDEX) && (_lines[i * 3 + P087_FIRST_FILTER_POS + 1].length() > 0)) { + if ((index >= 0) && (index < P87_MAX_CAPTURE_INDEX) && (_lines[i * 3 + P087_FIRST_FILTER_POS + 2].length() > 0)) { log += ' '; log += String(i); log += ':'; From 198f244887db1f9a4a54961224450fe1760af2a7 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 21 Mar 2020 11:24:36 +0100 Subject: [PATCH 27/40] Add generic hexToUL functions --- src/ESPEasy_fdwdecl.h | 4 ++++ src/StringConverter.ino | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/ESPEasy_fdwdecl.h b/src/ESPEasy_fdwdecl.h index ae75dce85..3774846f5 100644 --- a/src/ESPEasy_fdwdecl.h +++ b/src/ESPEasy_fdwdecl.h @@ -134,8 +134,12 @@ String formatIP(const IPAddress& ip); String toString(float value, byte decimals); String boolToString(bool value); bool isInt(const String& tBuf); +unsigned long hexToUL(const String& input_c); +unsigned long hexToUL(const String& input_c, size_t nrHexDecimals); +unsigned long hexToUL(const String& input_c, size_t startpos, size_t nrHexDecimals); String formatToHex(unsigned long value, const String& prefix); String formatToHex(unsigned long value); +String formatToHex_decimal(unsigned long value); String getNumerical(const String& tBuf, bool mustBeInteger); float getCPUload(); diff --git a/src/StringConverter.ino b/src/StringConverter.ino index 05f4a6ac3..34ea53e0c 100644 --- a/src/StringConverter.ino +++ b/src/StringConverter.ino @@ -69,6 +69,34 @@ String formatMAC(const uint8_t *mac) { return String(str); } + +/********************************************************************************************\ + Handling HEX strings + \*********************************************************************************************/ + +// Convert max. 8 hex decimals to unsigned long +unsigned long hexToUL(const String& input_c, size_t nrHexDecimals) { + size_t nr_decimals = nrHexDecimals; + if (nr_decimals > 8) { + nr_decimals = 8; + } + size_t inputLength = input_c.length(); + if (nr_decimals > inputLength) { + nr_decimals = inputLength; + } + String tmp = input_c.substring(0, nr_decimals); + return strtoul(tmp.c_str(), 0, 16); +} + +unsigned long hexToUL(const String& input_c) { + return hexToUL(input_c, input_c.length()); +} + +unsigned long hexToUL(const String& input_c, size_t startpos, size_t nrHexDecimals) { + return hexToUL(input_c.substring(startpos, startpos + nrHexDecimals), nrHexDecimals); +} + + String formatToHex(unsigned long value, const String& prefix) { String result = prefix; String hex(value, HEX); From b02684a6e27bc0f62e1ea72bbcad5660e86dcf24 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 21 Mar 2020 14:47:55 +0100 Subject: [PATCH 28/40] [WiFi] Start webserver before starting wifi (long delay to receive 1st byte) --- src/ESPEasy.ino | 2 ++ src/ESPEasyWifi.ino | 6 +++--- src/ESPEasyWifi_ProcessEvent.ino | 3 --- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index b745e6545..7b135149e 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -369,6 +369,8 @@ void setup() rulesProcessing(event); // TD-er: Process events in the setup() now. } + setWebserverRunning(true); + WiFiConnectRelaxed(); #ifdef FEATURE_REPORTING diff --git a/src/ESPEasyWifi.ino b/src/ESPEasyWifi.ino index 1e50904df..9eec41d8d 100644 --- a/src/ESPEasyWifi.ino +++ b/src/ESPEasyWifi.ino @@ -85,14 +85,15 @@ bool WiFiConnected() { // For ESP82xx, do not rely on WiFi.status() with event based wifi. const bool validWiFi = (WiFi.RSSI() < 0) && WiFi.isConnected() && hasIPaddr(); - + // FIXME TD-er: Not sure if this is needed as we also set it when processing WiFi events. +/* if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED) { if (validWiFi) { // Set internal wifiStatus and reset timer to disable AP mode markWiFi_services_initialized(); } } - +*/ if (wifiStatus == ESPEASY_WIFI_SERVICES_INITIALIZED) { if (validWiFi) { // Connected, thus disable any timer to start AP mode. (except when in WiFi setup mode) @@ -241,7 +242,6 @@ void resetWiFi() { processedScanDone = true; wifiConnectAttemptNeeded = true; WifiDisconnect(); -// setWebserverRunning(false); // setWifiMode(WIFI_OFF); diff --git a/src/ESPEasyWifi_ProcessEvent.ino b/src/ESPEasyWifi_ProcessEvent.ino index 1c5573c7f..120669308 100644 --- a/src/ESPEasyWifi_ProcessEvent.ino +++ b/src/ESPEasyWifi_ProcessEvent.ino @@ -128,7 +128,6 @@ void processDisconnect() { if (processedDisconnect) { return; } processedDisconnect = true; wifiStatus = ESPEASY_WIFI_DISCONNECTED; -// setWebserverRunning(false); delay(100); // FIXME TD-er: See https://github.com/letscontrolit/ESPEasy/issues/1987#issuecomment-451644424 if (Settings.UseRules) { @@ -312,7 +311,6 @@ void processConnectAPmode() { log += WiFi.softAPgetStationNum(); addLog(LOG_LEVEL_INFO, log); } - setWebserverRunning(true); // Start DNS, only used if the ESP has no valid WiFi config // It will reply with it's own address on all DNS requests @@ -420,5 +418,4 @@ void processScanDone() { void markWiFi_services_initialized() { wifiStatus = ESPEASY_WIFI_SERVICES_INITIALIZED; wifiConnectInProgress = false; - setWebserverRunning(true); } \ No newline at end of file From 902149af5e966b12760a98c496032fd4c37deef4 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 21 Mar 2020 14:48:29 +0100 Subject: [PATCH 29/40] [Serial Log] Keep a bit more free memory when processing serial log --- src/Serial.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Serial.ino b/src/Serial.ino index 0087eca8b..5d3aafc2a 100644 --- a/src/Serial.ino +++ b/src/Serial.ino @@ -47,12 +47,12 @@ void addToSerialBuffer(const char *line) { const size_t line_length = strlen(line); int roomLeft = getMaxFreeBlock(); - if (roomLeft < 500) { + if (roomLeft < 1000) { roomLeft = 0; // Do not append to buffer. - } else if (roomLeft < 3000) { + } else if (roomLeft < 4000) { roomLeft = 128 - serialWriteBuffer.size(); // 1 buffer. } else { - roomLeft -= 3000; // leave some free for normal use. + roomLeft -= 4000; // leave some free for normal use. } if (roomLeft > 0) { From 5afd1d3a8a5873c35291c07917005f5b222ae6b3 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 21 Mar 2020 14:50:16 +0100 Subject: [PATCH 30/40] [Serial Proxy] Don't process on empty regexp Also move the actual matching in the PLUGIN_READ part. --- src/_P087_SerialProxy.ino | 17 ++++++++------- src/src/PluginStructs/P087_data_struct.cpp | 24 ++++++++++++++-------- src/src/PluginStructs/P087_data_struct.h | 6 +++++- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/_P087_SerialProxy.ino b/src/_P087_SerialProxy.ino index ae419ca8e..6f17221ee 100644 --- a/src/_P087_SerialProxy.ino +++ b/src/_P087_SerialProxy.ino @@ -203,17 +203,9 @@ boolean Plugin_087(byte function, struct EventStruct *event, String& string) { static_cast(getPluginTaskData(event->TaskIndex)); if ((nullptr != P087_data) && P087_data->loop()) { - // schedule_task_device_timer(event->TaskIndex, millis() + 10); + schedule_task_device_timer(event->TaskIndex, millis() + 10); delay(0); // Processing a full sentence may take a while, run some // background tasks. - P087_data->getSentence(event->String2); - - if (event->String2.length() > 0) { - if (Plugin_087_match_all(event->TaskIndex, event->String2)) { - sendData(event); - addLog(LOG_LEVEL_INFO, event->String2); - } - } } success = true; } @@ -223,6 +215,13 @@ boolean Plugin_087(byte function, struct EventStruct *event, String& string) { case PLUGIN_READ: { P087_data_struct *P087_data = static_cast(getPluginTaskData(event->TaskIndex)); + if ((nullptr != P087_data) && P087_data->getSentence(event->String2)) { + if (Plugin_087_match_all(event->TaskIndex, event->String2)) { +// sendData(event); + addLog(LOG_LEVEL_DEBUG, event->String2); + success = true; + } + } if ((nullptr != P087_data)) {} break; diff --git a/src/src/PluginStructs/P087_data_struct.cpp b/src/src/PluginStructs/P087_data_struct.cpp index 2591058ef..c44f7ec5f 100644 --- a/src/src/PluginStructs/P087_data_struct.cpp +++ b/src/src/PluginStructs/P087_data_struct.cpp @@ -35,6 +35,7 @@ void P087_data_struct::post_init() { for (uint8_t i = 0; i < P87_MAX_CAPTURE_INDEX; ++i) { capture_index_used[i] = false; } + regex_empty = _lines[P087_REGEX_POS].length() == 0; String log = F("P087_post_init:"); for (uint8_t i = 0; i < P087_NR_FILTERS; ++i) { @@ -109,6 +110,8 @@ bool P087_data_struct::loop() { if (valid) { fullSentenceReceived = true; + last_sentence = sentence_part; + sentence_part = ""; } break; } @@ -127,14 +130,18 @@ bool P087_data_struct::loop() { if (fullSentenceReceived) { ++sentences_received; - length_last_received = sentence_part.length(); + length_last_received = last_sentence.length(); } return fullSentenceReceived; } -void P087_data_struct::getSentence(String& string) { - string = sentence_part; - sentence_part = ""; +bool P087_data_struct::getSentence(String& string) { + string = last_sentence; + if (string.length() == 0) { + return false; + } + last_sentence = ""; + return true; } void P087_data_struct::getSentencesReceived(uint32_t& succes, uint32_t& error, uint32_t& length_last) const { @@ -249,6 +256,10 @@ bool P087_data_struct::matchRegexp(String& received) const { if (strlength == 0) { return false; } + if (regex_empty || getMatchType() == Filter_Disabled) { + return true; + } + uint32_t regexp_match_length = getRegExpMatchLength(); @@ -261,10 +272,7 @@ bool P087_data_struct::matchRegexp(String& received) const { MatchState ms(const_cast(received.c_str()), strlength); bool match_result = false; - - if (getMatchType() == Filter_Disabled) { - match_result = true; - } else if (globalMatch()) { + if (globalMatch()) { capture_vector.clear(); ms.GlobalMatch(_lines[P087_REGEX_POS].c_str(), match_callback); const uint8_t vectorlength = capture_vector.size(); diff --git a/src/src/PluginStructs/P087_data_struct.h b/src/src/PluginStructs/P087_data_struct.h index 8cd58d7d0..6d3b0af0a 100644 --- a/src/src/PluginStructs/P087_data_struct.h +++ b/src/src/PluginStructs/P087_data_struct.h @@ -59,7 +59,9 @@ public: bool loop(); - void getSentence(String& string); + // Get the received sentence + // @retval true when the string is not empty. + bool getSentence(String& string); void getSentencesReceived(uint32_t& succes, uint32_t& error, @@ -109,6 +111,7 @@ private: ESPeasySerial *easySerial = nullptr; String sentence_part; + String last_sentence; uint16_t max_length = 550; uint32_t sentences_received = 0; uint32_t sentences_received_error = 0; @@ -119,6 +122,7 @@ private: bool capture_index_used[P87_MAX_CAPTURE_INDEX]; bool capture_index_must_not_match[P87_MAX_CAPTURE_INDEX]; + bool regex_empty = false; }; From 11ec14ed20e5c8e08c41e39d03a0ac05db276213 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 21 Mar 2020 15:06:18 +0100 Subject: [PATCH 31/40] Check if plugin uses formula before trying to process formula --- src/Controller.ino | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/Controller.ino b/src/Controller.ino index 98a7df4cf..478311725 100644 --- a/src/Controller.ino +++ b/src/Controller.ino @@ -488,21 +488,23 @@ void SensorSendTask(taskIndex_t TaskIndex) if (success) { - START_TIMER; - for (byte varNr = 0; varNr < VARS_PER_TASK; varNr++) - { - if (ExtraTaskSettings.TaskDeviceFormula[varNr][0] != 0) + if (Device[DeviceIndex].FormulaOption) { + START_TIMER; + for (byte varNr = 0; varNr < VARS_PER_TASK; varNr++) { - String formula = ExtraTaskSettings.TaskDeviceFormula[varNr]; - formula.replace(F("%pvalue%"), String(preValue[varNr])); - formula.replace(F("%value%"), String(UserVar[varIndex + varNr])); - float result = 0; - byte error = Calculate(formula.c_str(), &result); - if (error == 0) - UserVar[varIndex + varNr] = result; + if (ExtraTaskSettings.TaskDeviceFormula[varNr][0] != 0) + { + String formula = ExtraTaskSettings.TaskDeviceFormula[varNr]; + formula.replace(F("%pvalue%"), String(preValue[varNr])); + formula.replace(F("%value%"), String(UserVar[varIndex + varNr])); + float result = 0; + byte error = Calculate(formula.c_str(), &result); + if (error == 0) + UserVar[varIndex + varNr] = result; + } } + STOP_TIMER(COMPUTE_FORMULA_STATS); } - STOP_TIMER(COMPUTE_FORMULA_STATS); sendData(&TempEvent); } } From b3c0f6e812a743e724f5839668ac6993dc26dcc5 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sun, 22 Mar 2020 01:41:53 +0100 Subject: [PATCH 32/40] [ESP32] Fix crash in startup connecting to WiFi (#2960 ) Fixes: #2960 --- src/ESPEasy.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ESPEasy.ino b/src/ESPEasy.ino index 7b135149e..3ac337d5e 100644 --- a/src/ESPEasy.ino +++ b/src/ESPEasy.ino @@ -369,10 +369,10 @@ void setup() rulesProcessing(event); // TD-er: Process events in the setup() now. } - setWebserverRunning(true); - WiFiConnectRelaxed(); + setWebserverRunning(true); + #ifdef FEATURE_REPORTING ReportStatus(); #endif From c39975a985093842e6f48904d74ae6891de4367b Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 22 Mar 2020 14:30:30 +0100 Subject: [PATCH 33/40] Fix ArduinoIDE Build error due to missing include As reported here: https://github.com/letscontrolit/ESPEasy/commit/c5c22643c62f725c22d80e55d3360885cf017baa#r37971537 --- src/WebServer_fwddecl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/WebServer_fwddecl.h b/src/WebServer_fwddecl.h index 739dd7435..d883d1695 100644 --- a/src/WebServer_fwddecl.h +++ b/src/WebServer_fwddecl.h @@ -3,6 +3,7 @@ #include "limits.h" #include "StringProviderTypes.h" +#include "src/Helpers/SystemVariables.h" // ******************************************************************************** @@ -112,4 +113,4 @@ void addSelector(const String& id, boolean reloadonchange = false, bool enabled = true); -#endif // WEBSERVER_FWD_DECL_H \ No newline at end of file +#endif // WEBSERVER_FWD_DECL_H From b261a215105e236890ff4b686c57940edfc653af Mon Sep 17 00:00:00 2001 From: Bartlomiej Zimon Date: Mon, 23 Mar 2020 00:01:10 +0000 Subject: [PATCH 34/40] [SysVars] small optimization --- src/src/Helpers/SystemVariables.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/src/Helpers/SystemVariables.cpp b/src/src/Helpers/SystemVariables.cpp index 82898126c..8d8d0a442 100644 --- a/src/src/Helpers/SystemVariables.cpp +++ b/src/src/Helpers/SystemVariables.cpp @@ -73,8 +73,7 @@ void SystemVariables::parseSystemVariables(String& s, boolean useURLencode) case BSSID: value = String((wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? F("00:00:00:00:00:00") : WiFi.BSSIDstr()); break; case CR: value = "\r"; break; case IP: value = getValue(LabelType::IP_ADDRESS); break; - case IP4: value = WiFi.localIP().toString().substring(WiFi.localIP().toString().lastIndexOf('.') + 1); break; // 4th IP - // octet + case IP4: value.concat( (int) WiFi.localIP()[3] ); break; // 4th IP octet #ifdef USES_MQTT case ISMQTT: value = String(MQTTclient_connected); break; #else // ifdef USES_MQTT From 5b24b58d2a8f0dfcea4e1bca4249c58fd5dc265e Mon Sep 17 00:00:00 2001 From: Bartlomiej Zimon Date: Mon, 23 Mar 2020 00:26:01 +0000 Subject: [PATCH 35/40] [SysVars] concat->String() --- src/src/Helpers/SystemVariables.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/Helpers/SystemVariables.cpp b/src/src/Helpers/SystemVariables.cpp index 8d8d0a442..2a8fa647c 100644 --- a/src/src/Helpers/SystemVariables.cpp +++ b/src/src/Helpers/SystemVariables.cpp @@ -73,7 +73,7 @@ void SystemVariables::parseSystemVariables(String& s, boolean useURLencode) case BSSID: value = String((wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? F("00:00:00:00:00:00") : WiFi.BSSIDstr()); break; case CR: value = "\r"; break; case IP: value = getValue(LabelType::IP_ADDRESS); break; - case IP4: value.concat( (int) WiFi.localIP()[3] ); break; // 4th IP octet + case IP4: value = String( (int) WiFi.localIP()[3] ); break; // 4th IP octet #ifdef USES_MQTT case ISMQTT: value = String(MQTTclient_connected); break; #else // ifdef USES_MQTT From 793878262d691b882239bf45eb24dcca8bfb014b Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Thu, 26 Mar 2020 16:51:11 +0100 Subject: [PATCH 36/40] [SGP30] Fix output all values to controller See discussion here: https://github.com/letscontrolit/ESPEasy/issues/2586#issuecomment-604416401 --- src/_P083_SGP30.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_P083_SGP30.ino b/src/_P083_SGP30.ino index 55c14205d..db2121498 100644 --- a/src/_P083_SGP30.ino +++ b/src/_P083_SGP30.ino @@ -38,7 +38,7 @@ boolean Plugin_083(byte function, struct EventStruct *event, String& string) { Device[++deviceCount].Number = PLUGIN_ID_083; Device[deviceCount].Type = DEVICE_TYPE_I2C; - Device[deviceCount].VType = SENSOR_TYPE_SINGLE; + Device[deviceCount].VType = SENSOR_TYPE_DUAL; Device[deviceCount].Ports = 0; Device[deviceCount].PullUpOption = false; Device[deviceCount].InverseLogicOption = false; From 8529ebed3b8897519b77698e45f6e14334c268e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Schr=C3=B6der?= Date: Fri, 27 Mar 2020 14:13:48 +0100 Subject: [PATCH 37/40] Fix double-Ok at command output --- src/_P091_SerSwitch.ino | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/_P091_SerSwitch.ino b/src/_P091_SerSwitch.ino index f7ba23252..12aafcb6f 100644 --- a/src/_P091_SerSwitch.ino +++ b/src/_P091_SerSwitch.ino @@ -622,8 +622,6 @@ boolean Plugin_091(byte function, struct EventStruct *event, String& string) log += F(":"); log += rcmd; addLog(LOG_LEVEL_INFO, log); - log = F("Ok"); - SendStatus(event->Source, log); } if ( command == F("relaypulse") ) @@ -674,8 +672,6 @@ boolean Plugin_091(byte function, struct EventStruct *event, String& string) log += String(event->Par3); log += F(" mS"); addLog(LOG_LEVEL_INFO, log); - log = F("\nOk"); - SendStatus(event->Source, log); } if ( command == F("relaylongpulse") ) @@ -727,8 +723,6 @@ boolean Plugin_091(byte function, struct EventStruct *event, String& string) log += String(event->Par3); log += F(" sec"); addLog(LOG_LEVEL_INFO, log); - log = F("\nOk"); - SendStatus(event->Source, log); } if ( command == F("ydim") ) // deal with dimmer command { @@ -756,11 +750,10 @@ boolean Plugin_091(byte function, struct EventStruct *event, String& string) } log += event->Par1; addLog(LOG_LEVEL_INFO, log); - log = F("\nOk"); } else { - log = F("\nNot supported"); + log = F("\nYDim not supported"); + SendStatus(event->Source, log); } - SendStatus(event->Source, log); } } From 5e99087ec6933dd8142e7c953c2b63e48f856583 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 28 Mar 2020 01:36:34 +0100 Subject: [PATCH 38/40] [PIO] feature/stage no longer available for building latest core libs --- platformio_core_defs.ini | 8 +++++--- platformio_esp82xx_base.ini | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index b9df27f99..d397de164 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -125,24 +125,26 @@ build_flags = ${esp82xx_2_6_x.build_flags} -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 [core_2_6_3] -platform = espressif8266@2.3.2 +platform = espressif8266@2.4.0 platform_packages = framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#2.6.3 build_flags = ${esp82xx_2_6_x.build_flags} -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191122 [core_2_6_3_sdk3] -platform = espressif8266@2.3.2 +platform = espressif8266@2.4.0 platform_packages = framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#2.6.3 build_flags = ${esp82xx_2_6_x.build_flags} -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 [core_stage] -platform = https://github.com/platformio/platform-espressif8266.git#feature/stage +platform = https://github.com/platformio/platform-espressif8266.git build_flags = ${esp82xx_2_6_x.build_flags} -DARDUINO_ESP8266_RELEASE='"2.7.0-dev stage"' -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191105 +platform_packages = + framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git [core_esp32_1_11_2] platform = espressif32@1.11.2 diff --git a/platformio_esp82xx_base.ini b/platformio_esp82xx_base.ini index 25762dee1..cb71d6515 100644 --- a/platformio_esp82xx_base.ini +++ b/platformio_esp82xx_base.ini @@ -21,6 +21,7 @@ platform_packages = ${core_2_6_3_sdk3.platform_packages} build_unflags = build_flags = ${core_stage.build_flags} platform = ${core_stage.platform} +platform_packages = ${core_stage.platform_packages} From cb99058d05ae69f745e2019a4970dd9e6a034371 Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sat, 28 Mar 2020 02:07:15 +0100 Subject: [PATCH 39/40] [PIO] Use platform_packages for all core libs supporting those --- platformio_core_defs.ini | 1 - platformio_esp82xx_base.ini | 2 ++ platformio_esp82xx_envs.ini | 16 ++++++++++++++++ platformio_special_envs.ini | 1 + 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index d397de164..ade9c4545 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -141,7 +141,6 @@ build_flags = ${esp82xx_2_6_x.build_flags} [core_stage] platform = https://github.com/platformio/platform-espressif8266.git build_flags = ${esp82xx_2_6_x.build_flags} - -DARDUINO_ESP8266_RELEASE='"2.7.0-dev stage"' -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191105 platform_packages = framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git diff --git a/platformio_esp82xx_base.ini b/platformio_esp82xx_base.ini index cb71d6515..d585c96bf 100644 --- a/platformio_esp82xx_base.ini +++ b/platformio_esp82xx_base.ini @@ -48,6 +48,7 @@ build_flags = ${regular_platform.build_flags} [normal_beta] platform = ${beta_platform.platform} +platform_packages = ${beta_platform.platform_packages} build_flags = ${beta_platform.build_flags} @@ -63,6 +64,7 @@ build_flags = ${regular_platform.build_flags} -DPLUGIN_BUILD_TESTI [testing_beta] platform = ${beta_platform.platform} +platform_packages = ${beta_platform.platform_packages} build_flags = ${beta_platform.build_flags} -DPLUGIN_BUILD_TESTING diff --git a/platformio_esp82xx_envs.ini b/platformio_esp82xx_envs.ini index b09749353..239c35eb5 100644 --- a/platformio_esp82xx_envs.ini +++ b/platformio_esp82xx_envs.ini @@ -27,6 +27,7 @@ extra_scripts = pre:pre_custom_esp82xx.py [env:custom_sdk3_ESP8266_4M1M] extends = esp8266_4M1M platform = ${core_2_6_3_sdk3.platform} +platform_packages = ${core_2_6_3_sdk3.platform_packages} build_flags = ${core_2_6_3_sdk3.build_flags} ${esp8266_4M1M.build_flags} -DPLUGIN_BUILD_CUSTOM @@ -37,6 +38,7 @@ extra_scripts = pre:pre_custom_esp82xx.py [env:custom_beta_ESP8266_4M1M] extends = esp8266_4M1M platform = ${beta_platform.platform} +platform_packages = ${beta_platform.platform_packages} build_flags = ${beta_platform.build_flags} ${esp8266_4M1M.build_flags} -DPLUGIN_BUILD_CUSTOM @@ -84,6 +86,7 @@ build_flags = ${regular_platform.build_flags} [env:normal_sdk3_ESP8266_1M] extends = esp8266_1M platform = ${core_2_6_3_sdk3.platform} +platform_packages = ${core_2_6_3_sdk3.platform_packages} build_flags = ${core_2_6_3_sdk3.build_flags} ${esp8266_1M.build_flags} @@ -184,6 +187,7 @@ build_flags = ${regular_platform.build_flags} [env:minimal_core_263_sdk3_ESP8266_1M_OTA_Domoticz] extends = esp8266_1M_OTA platform = ${core_2_6_3_sdk3.platform} +platform_packages = ${core_2_6_3_sdk3.platform_packages} build_flags = ${core_2_6_3_sdk3.build_flags} ${esp8266_1M_OTA.build_flags} ${minimal_OTA_domoticz.build_flags} @@ -191,6 +195,7 @@ build_flags = ${core_2_6_3_sdk3.build_flags} [env:minimal_core_263_sdk3_ESP8285_1M_OTA_Domoticz] extends = esp8285_1M_OTA platform = ${core_2_6_3_sdk3.platform} +platform_packages = ${core_2_6_3_sdk3.platform_packages} build_flags = ${core_2_6_3_sdk3.build_flags} ${esp8285_1M_OTA.build_flags} ${minimal_OTA_domoticz.build_flags} @@ -215,6 +220,7 @@ build_flags = ${regular_platform.build_flags} [env:minimal_core_263_sdk3_ESP8266_1M_OTA_FHEM_HA] extends = esp8266_1M_OTA platform = ${core_2_6_3_sdk3.platform} +platform_packages = ${core_2_6_3_sdk3.platform_packages} build_flags = ${core_2_6_3_sdk3.build_flags} ${esp8266_1M_OTA.build_flags} ${minimal_OTA_FHEM_HA.build_flags} @@ -222,6 +228,7 @@ build_flags = ${core_2_6_3_sdk3.build_flags} [env:minimal_core_263_sdk3_ESP8285_1M_OTA_FHEM_HA] extends = esp8285_1M_OTA platform = ${core_2_6_3_sdk3.platform} +platform_packages = ${core_2_6_3_sdk3.platform_packages} build_flags = ${core_2_6_3_sdk3.build_flags} ${esp8285_1M_OTA.build_flags} ${minimal_OTA_FHEM_HA.build_flags} @@ -239,6 +246,7 @@ build_flags = ${core_2_6_3_sdk3.build_flags} [env:minimal_IRext_ESP8266_1M] extends = esp8266_1M platform = ${minimal_ir_extended.platform} +platform_packages = ${minimal_ir_extended.platform_packages} lib_ignore = ${minimal_ir_extended.lib_ignore} build_flags = ${minimal_ir_extended.build_flags} ${esp8266_1M.build_flags} @@ -252,6 +260,7 @@ build_unflags = ${esp8266_1M_OTA.build_unflags} -DPLUGIN_BUILD_NORMA [env:minimal_IRext_ESP8266_4M1M] extends = esp8266_4M1M platform = ${minimal_ir_extended.platform} +platform_packages = ${minimal_ir_extended.platform_packages} lib_ignore = ${minimal_ir_extended.lib_ignore} build_flags = ${minimal_ir_extended.build_flags} ${esp8266_4M1M.build_flags} @@ -260,6 +269,7 @@ build_flags = ${minimal_ir_extended.build_flags} [env:minimal_IRext_ESP8266_4M2M] extends = esp8266_4M2M platform = ${minimal_ir_extended.platform} +platform_packages = ${minimal_ir_extended.platform_packages} lib_ignore = ${minimal_ir_extended.lib_ignore} build_flags = ${minimal_ir_extended.build_flags} ${esp8266_4M2M.build_flags} @@ -272,6 +282,7 @@ build_flags = ${minimal_ir_extended.build_flags} [env:normal_IRext_no_rx_ESP8266_4M2M] extends = esp8266_4M2M platform = ${normal_ir_extended_no_rx.platform} +platform_packages = ${normal_ir_extended_no_rx.platform_packages} lib_ignore = ${normal_ir_extended_no_rx.lib_ignore} build_flags = ${normal_ir_extended_no_rx.build_flags} ${esp8266_4M2M.build_flags} @@ -288,6 +299,7 @@ build_flags = ${normal_ir_extended_no_rx.build_flags} [env:test_ESP8266_4M1M_VCC] extends = esp8266_4M1M platform = ${testing.platform} +platform_packages = ${testing.platform_packages} build_flags = ${testing.build_flags} ${esp8266_4M1M.build_flags} -DFEATURE_ADC_VCC=true @@ -296,6 +308,7 @@ build_flags = ${testing.build_flags} [env:test_ESP8266_4M1M_VCC_MDNS_SD] extends = esp8266_4M1M platform = ${testing.platform} +platform_packages = ${testing.platform_packages} build_flags = ${testing.build_flags} ${esp8266_4M1M.build_flags} -DFEATURE_ADC_VCC=true @@ -307,6 +320,7 @@ lib_ignore = ESP32_ping, ESP32WebServer, IRremoteESP8266, Heatpum [env:test_beta_ESP8266_4M1M] extends = esp8266_4M1M platform = ${testing_beta.platform} +platform_packages = ${testing_beta.platform_packages} build_flags = ${testing_beta.build_flags} ${esp8266_4M1M.build_flags} @@ -314,6 +328,7 @@ build_flags = ${testing_beta.build_flags} [env:test_beta_ESP8266_16M] extends = esp8266_16M platform = ${testing_beta.platform} +platform_packages = ${testing_beta.platform_packages} build_flags = ${testing_beta.build_flags} ${esp8266_16M.build_flags} -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22y @@ -333,6 +348,7 @@ build_flags = ${testing_beta.build_flags} [env:dev_ESP8266_4M1M] extends = esp8266_4M1M platform = ${dev.platform} +platform_packages = ${dev.platform_packages} build_flags = ${dev.build_flags} ${esp8266_4M1M.build_flags} diff --git a/platformio_special_envs.ini b/platformio_special_envs.ini index a04259086..00b417f71 100644 --- a/platformio_special_envs.ini +++ b/platformio_special_envs.ini @@ -27,6 +27,7 @@ extra_scripts = pre:pre_custom_esp82xx.py [env:spec_debug_beta_custom_ESP8266_4M1M] extends = esp8266_4M1M, debug_pio platform = ${beta_platform.platform} +platform_packages = ${beta_platform.platform_packages} build_flags = ${beta_platform.build_flags} ${debug_pio.build_flags} ${esp8266_4M1M.build_flags} From 4d2eddbcdee64623d6d145bcaedc59e3cc747168 Mon Sep 17 00:00:00 2001 From: TD-er Date: Sat, 28 Mar 2020 02:55:55 +0100 Subject: [PATCH 40/40] automatically updated release notes for mega-20200328 --- dist/Release_notes.txt | 123 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/dist/Release_notes.txt b/dist/Release_notes.txt index e2cf7894d..ab33bceb6 100644 --- a/dist/Release_notes.txt +++ b/dist/Release_notes.txt @@ -1,3 +1,126 @@ +------------------------------------------------- +Changes in release mega-20200328 (since mega-20200310) +------------------------------------------------- + +Release date: za 28 mrt 2020 2:55:55 CET + +Bartlomiej Zimon (2): + [SysVars] small optimization + [SysVars] concat->String() + +Boris Krivonog (30): + Initial commit of the Mitsibutshi HP integration. + Added device values. + first contact + push on change + push on change + unified code read and update + added update ... + set temperature ... + write all parameters + logging ... + logs fixed + if update was successful, update settings immediatelly + renamed to settings + don't read during write, don't request info we don't care about ... + Added info about which specific commit used. + reverted changes made in other files + reverted changes made in other files + reverted changes made in other files + fixed compile time warnings + Renamed to 092 plugin. + Rewrote communication part, removed delays from code, optimised handling and storing of data ... + Write re-enabled + Renamed to 093 plugin. + Renamed to 093 plugin. + Improved write operations + Fixed build when debug is disabled + Make sure to break out of switch-case. + Handle only "MHP" commands + adding documentation ... + adding documentation ... + +Gijs Noorlander (47): + [P091] Move P165 SerSwitch from playground to main repository + [P091] Add documentation + [P091 SerSwitch] Update to use latest sources of enesbcs + Minify the JS code + store in flash + [Docs] Add stub for documentation of P093 - Mitsubishi Heat Pump + [SC16IS752] Add Library + [SC16IS752 lib] Update manifest to register as PIO library + [ESPEasySerial] Update manifest to mark SC16IS752 dependency + [SC16IS752] Use I2C-UART bridge in ESPEasySerial (ESP8266) + [SC16IS752] Extend Serial Helper to support I2C UART + Fix warnings in ccronexpr test code + [Serial] Mark plugins using serial as device type serial + [I2C serial] Disable debugging + [Docs] Add port type to plugin substitutions + [Docs] Mark all plugins using Serial as port type + [I2C UART] Speed up reading from I2C Serial + [I2C UART] Cache FIFO available to speed up reading + [I2C UART] Limit calls to serial.available() + [code analytics] Use PVS studio + [ESP32] Add SDS011 support for ESP32 + [Task] Start scheduled runs again after (re)enableTask command + [I2C UART] Mark ESPEasySerial library as v2.0.0 + [ESP32] Make sure to include the version tag in ESPEasySerial libdeb + [I2C] Add I2C frequency setting + ESPEasy Status LED is not working on ESP32 with buildin LED (#2940) + Pulse Counter must retain its values after reboot (#2268) + [Build] Disable test_ESP8266_4M1M_VCC_MDNS_SD due to max sketch size + [JSON] Fix JSON output of values for single task + [SerialProxy] Add regexp filtering + [Lib] Add RegExp lib + [Serial Proxy] Add regexp filtering using captures + [Serial Proxy] Add extra filter parameters + [Serial Proxy] Move plugin specific struct to .h/.cpp to support captures + [Serial Proxy] Use capture filtering + [Web] Make command field on Tools page much wider + [Serial Proxy] Only check on valid filter rules + [SysVar] Add extra system variables to get build info + [Serial Proxy] Fix check in empty string test + Add generic hexToUL functions + [WiFi] Start webserver before starting wifi (long delay to receive 1st byte) + [Serial Log] Keep a bit more free memory when processing serial log + [Serial Proxy] Don't process on empty regexp + Check if plugin uses formula before trying to process formula + [ESP32] Fix crash in startup connecting to WiFi (#2960 ) + [SGP30] Fix output all values to controller + [PIO] feature/stage no longer available for building latest core libs + [PIO] Use platform_packages for all core libs supporting those + +Grovkillen (8): + [rules] commented out old upload html + [rules] forms uncommented (needed for rules set) + [rules] removed the "onSubmit" event + [rules] narrowed scope of form (to not trigger onChange if btn clicked) + [rules] file upload instead of form upload + [rules] removed commented code + [rules] size is updated when saved + [rules] td-er talked me into it... thanks mate! + +Michael Schröder (1): + Fix double-Ok at command output + +TD-er (4): + Start of implementing SC16IS752 support + Fix resetpulsecounter for P003_Pulse (#2710) + [Blynk] Fix building C015 Blynk controller + Fix ArduinoIDE Build error due to missing include + +borisk (6): + Updating documentation + Updating documentation + Updating documentation + Add as part of testing plugins ... + Restructured docs a bit so its easier to follow + updated docs + +tonhuisman (2): + [P023] Fix for text overflowing onto next line(s) + Added condition for 64x48 and rotated combined + + ------------------------------------------------- Changes in release mega-20200310 (since mega-20200305) -------------------------------------------------