commit
b13c5e8788
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@ |
|||||||
|
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(m){if(void 0===m)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===m.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var l="2"==m.version[0];m.ja=function(){this.pipeline.reset(),this.pipeline.add(m.ja.trimmer,m.ja.stopWordFilter,m.ja.stemmer),l?this.tokenizer=m.ja.tokenizer:(m.tokenizer&&(m.tokenizer=m.ja.tokenizer),this.tokenizerFn&&(this.tokenizerFn=m.ja.tokenizer))};var j=new m.TinySegmenter;m.ja.tokenizer=function(e){var r,t,i,n,o,s,p,a,u;if(!arguments.length||null==e||null==e)return[];if(Array.isArray(e))return e.map(function(e){return l?new m.Token(e.toLowerCase()):e.toLowerCase()});for(r=(t=e.toString().toLowerCase().replace(/^\s+/,"")).length-1;0<=r;r--)if(/\S/.test(t.charAt(r))){t=t.substring(0,r+1);break}for(o=[],i=t.length,p=a=0;a<=i;a++)if(s=a-p,t.charAt(a).match(/\s/)||a==i){if(0<s)for(n=j.segment(t.slice(p,a)).filter(function(e){return!!e}),u=p,r=0;r<n.length;r++)l?o.push(new m.Token(n[r],{position:[u,n[r].length],index:o.length})):o.push(n[r]),u+=n[r].length;p=a+1}return o},m.ja.stemmer=function(e){return e},m.Pipeline.registerFunction(m.ja.stemmer,"stemmer-ja"),m.ja.wordCharacters="一二三四五六七八九十百千万億兆一-龠々〆ヵヶぁ-んァ-ヴーア-ン゙a-zA-Za-zA-Z0-90-9",m.ja.trimmer=m.trimmerSupport.generateTrimmer(m.ja.wordCharacters),m.Pipeline.registerFunction(m.ja.trimmer,"trimmer-ja"),m.ja.stopWordFilter=m.generateStopWordFilter("これ それ あれ この その あの ここ そこ あそこ こちら どこ だれ なに なん 何 私 貴方 貴方方 我々 私達 あの人 あのかた 彼女 彼 です あります おります います は が の に を で え から まで より も どの と し それで しかし".split(" ")),m.Pipeline.registerFunction(m.ja.stopWordFilter,"stopWordFilter-ja"),m.jp=m.ja,m.Pipeline.registerFunction(m.jp.stemmer,"stemmer-jp"),m.Pipeline.registerFunction(m.jp.trimmer,"trimmer-jp"),m.Pipeline.registerFunction(m.jp.stopWordFilter,"stopWordFilter-jp")}}); |
@ -1 +1 @@ |
|||||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(n){if(void 0===n)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===n.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i="2"==n.version[0];n.jp=function(){this.pipeline.reset(),this.pipeline.add(n.jp.stopWordFilter,n.jp.stemmer),i?this.tokenizer=n.jp.tokenizer:(n.tokenizer&&(n.tokenizer=n.jp.tokenizer),this.tokenizerFn&&(this.tokenizerFn=n.jp.tokenizer))};var o=new n.TinySegmenter;n.jp.tokenizer=function(e){if(!arguments.length||null==e||null==e)return[];if(Array.isArray(e))return e.map(function(e){return i?new n.Token(e.toLowerCase()):e.toLowerCase()});for(var r=e.toString().toLowerCase().replace(/^\s+/,""),t=r.length-1;0<=t;t--)if(/\S/.test(r.charAt(t))){r=r.substring(0,t+1);break}return o.segment(r).filter(function(e){return!!e}).map(function(e){return i?new n.Token(e):e})},n.jp.stemmer=function(e){return e},n.Pipeline.registerFunction(n.jp.stemmer,"stemmer-jp"),n.jp.wordCharacters="一二三四五六七八九十百千万億兆一-龠々〆ヵヶぁ-んァ-ヴーア-ン゙a-zA-Za-zA-Z0-90-9",n.jp.stopWordFilter=function(e){if(-1===n.jp.stopWordFilter.stopWords.indexOf(i?e.toString():e))return e},n.jp.stopWordFilter=n.generateStopWordFilter("これ それ あれ この その あの ここ そこ あそこ こちら どこ だれ なに なん 何 私 貴方 貴方方 我々 私達 あの人 あのかた 彼女 彼 です あります おります います は が の に を で え から まで より も どの と し それで しかし".split(" ")),n.Pipeline.registerFunction(n.jp.stopWordFilter,"stopWordFilter-jp")}}); |
module.exports=require("./lunr.ja"); |
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@ |
|||||||
|
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(t){if(void 0===t)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===t.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i="2"==t.version[0];t.th=function(){this.pipeline.reset(),this.pipeline.add(t.th.trimmer),i?this.tokenizer=t.th.tokenizer:(t.tokenizer&&(t.tokenizer=t.th.tokenizer),this.tokenizerFn&&(this.tokenizerFn=t.th.tokenizer))},t.th.wordCharacters="[-]",t.th.trimmer=t.trimmerSupport.generateTrimmer(t.th.wordCharacters),t.Pipeline.registerFunction(t.th.trimmer,"trimmer-th");var n=t.wordcut;n.init(),t.th.tokenizer=function(e){if(!arguments.length||null==e||null==e)return[];if(Array.isArray(e))return e.map(function(e){return i?new t.Token(e):e});var r=e.toString().replace(/^\s+/,"");return n.cut(r).split("|")}}}); |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 120 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 179 KiB |
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -0,0 +1,384 @@ |
|||||||
|
## Uploading file from Web Browser |
||||||
|
|
||||||
|
If you have to write some data individually to the ESP8266/ESP32 module for the sketch behavior, the [AutoConnectFile](acelements.md#autoconnectfile) element will assist with your wants implementation. The AutoConnectFile element produces an HTML `<input type="file">` tag and can save uploaded file to the flash or external SD of the ESP8266/ESP32 module. The handler for saving is built into AutoConnect. You can use it to inject any sketch data such as the initial values for the custom Web page into the ESP module via OTA without using the sketch data upload tool of Arduino-IDE. |
||||||
|
<p style="display:block;margin-left:auto;margin-right:auto;width:603px;height:368px;border:1px solid lightgray;"><img data-gifffer="images/upload.gif" data-gifffer-width="601" data-gifffer-height="366""/></p> |
||||||
|
|
||||||
|
## Basic steps of the file upload sketch |
||||||
|
|
||||||
|
Here is the basic procedure of the sketch which can upload files from the client browser using AutoConnectFile:[^1] |
||||||
|
|
||||||
|
[^1]:The AutoConnectFile element can be used with other AutoConnectElements on the same page. |
||||||
|
|
||||||
|
1. Place AutoConnectFile on a custom Web page by writing JSON or constructor code directly with the sketch. |
||||||
|
2. Place other AutoConnectElements as needed. |
||||||
|
3. Place AutoConnectSubmit on the same custom Web page. |
||||||
|
4. Perform the following process in the on-handler of submitting destination: |
||||||
|
- Retrieve the [AutoConnectFile instance](apielements.md#autoconnectfile) from the custom Web page where you placed the AutoConnectFile element using the [AutoConnectAux::getElement](apiaux.md#getelement) function or the [operator \[\]](apiaux.md#operator). |
||||||
|
- Start access to the device specified as the upload destination. In usually, it depends on the file system's begin function. For example, if you specified Flash's SPIFFS as the upload destination, invokes *SPIFFS.begin()*. |
||||||
|
- The [value member](acelements.md#value_3) of AutoConnectFile contains the file name of the upload file. Use its file name to access the uploaded file on the device. |
||||||
|
- Invokes the end function associated with the begin to close the device. It is the *SPIFFS.end()** if the flash on the ESP module has been begun for SPIFFS. |
||||||
|
|
||||||
|
The following sketch is an example that implements the above basic steps. The *postUpload* function is the on-handler and retrieves the AutoConnectFile as named `upload_file`. You should note that this handler is **not** for a custom Web page placed with its AutoConnectFile element. The uploaded file should be processed by the handler for the transition destination page from the AutoConnectFile element placed page. AutoConnect built-in upload handler will save the uploaded file to the specified device before invoking the *postUpload* function. |
||||||
|
|
||||||
|
However, If you use uploaded files in different situations, it may be more appropriate to place the actual handling process outside the handler. It applies for the parameter file, etc. The important thing is that you do not have to sketch file reception and storing logic by using the AutoConnectFile element and the upload handler built into the AutoConnect. |
||||||
|
|
||||||
|
```cpp hl_lines="14 53 64 67 70 86" |
||||||
|
#include <ESP8266WiFi.h> |
||||||
|
#include <ESP8266WebServer.h> |
||||||
|
#include <FS.h> |
||||||
|
#include <AutoConnect.h> |
||||||
|
|
||||||
|
// Upload request custom Web page |
||||||
|
static const char PAGE_UPLOAD[] PROGMEM = R"( |
||||||
|
{ |
||||||
|
"uri": "/", |
||||||
|
"title": "Upload", |
||||||
|
"menu": true, |
||||||
|
"element": [ |
||||||
|
{ "name":"caption", "type":"ACText", "value":"<h2>File uploading platform<h2>" }, |
||||||
|
{ "name":"upload_file", "type":"ACFile", "label":"Select file: ", "store":"fs" }, |
||||||
|
{ "name":"upload", "type":"ACSubmit", "value":"UPLOAD", "uri":"/upload" } |
||||||
|
] |
||||||
|
} |
||||||
|
)"; |
||||||
|
|
||||||
|
// Upload result display |
||||||
|
static const char PAGE_BROWSE[] PROGMEM = R"( |
||||||
|
{ |
||||||
|
"uri": "/upload", |
||||||
|
"title": "Upload", |
||||||
|
"menu": false, |
||||||
|
"element": [ |
||||||
|
{ "name":"caption", "type":"ACText", "value":"<h2>Uploading ended<h2>" }, |
||||||
|
{ "name":"filename", "type":"ACText" }, |
||||||
|
{ "name":"size", "type":"ACText", "format":"%s bytes uploaded" }, |
||||||
|
{ "name":"content_type", "type":"ACText", "format":"Content: %s" } |
||||||
|
] |
||||||
|
} |
||||||
|
)"; |
||||||
|
|
||||||
|
ESP8266WebServer server; |
||||||
|
AutoConnect portal(server); |
||||||
|
// Declare AutoConnectAux separately as a custom web page to access |
||||||
|
// easily for each page in the post-upload handler. |
||||||
|
AutoConnectAux auxUpload; |
||||||
|
AutoConnectAux auxBrowse; |
||||||
|
|
||||||
|
/** |
||||||
|
* Post uploading, AutoConnectFile's built-in upload handler reads the |
||||||
|
* file saved in SPIFFS and displays the file contents on /upload custom |
||||||
|
* web page. However, only files with mime type uploaded as text are |
||||||
|
* displayed. A custom web page handler is called after upload. |
||||||
|
* @param aux AutoConnectAux(/upload) |
||||||
|
* @param args PageArgument |
||||||
|
* @return Uploaded text content |
||||||
|
*/ |
||||||
|
String postUpload(AutoConnectAux& aux, PageArgument& args) { |
||||||
|
String content; |
||||||
|
AutoConnectFile& upload = auxUpload["upload_file"].as<AutoConnectFile>(); |
||||||
|
AutoConnectText& aux_filename = aux["filename"].as<AutoConnectText>(); |
||||||
|
AutoConnectText& aux_size = aux["size"].as<AutoConnectText>(); |
||||||
|
AutoConnectText& aux_contentType = aux["content_type"].as<AutoConnectText>(); |
||||||
|
// Assignment operator can be used for the element attribute. |
||||||
|
aux_filename.value = upload.value; |
||||||
|
aux_size.value = String(upload.size); |
||||||
|
aux_contentType.value = upload.mimeType; |
||||||
|
// The file saved by the AutoConnect upload handler is read from |
||||||
|
// the EEPROM and echoed to a custom web page. |
||||||
|
SPIFFS.begin(); |
||||||
|
File uploadFile = SPIFFS.open(String("/" + upload.value).c_str(), "r"); |
||||||
|
if (uploadFile) { |
||||||
|
while (uploadFile.available()) { |
||||||
|
char c = uploadFile.read(); |
||||||
|
Serial.print(c); |
||||||
|
} |
||||||
|
uploadFile.close(); |
||||||
|
} |
||||||
|
else |
||||||
|
content = "Not saved"; |
||||||
|
SPIFFS.end(); |
||||||
|
return String(); |
||||||
|
} |
||||||
|
|
||||||
|
void setup() { |
||||||
|
delay(1000); |
||||||
|
Serial.begin(115200); |
||||||
|
Serial.println(); |
||||||
|
|
||||||
|
auxUpload.load(PAGE_UPLOAD); |
||||||
|
auxBrowse.load(PAGE_BROWSE); |
||||||
|
portal.join({ auxUpload, auxBrowse }); |
||||||
|
auxBrowse.on(postUpload); |
||||||
|
portal.begin(); |
||||||
|
} |
||||||
|
|
||||||
|
void loop() { |
||||||
|
portal.handleClient(); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
## Where will the file upload |
||||||
|
|
||||||
|
The AutoConnect built-in upload handler can save the upload file to three locations: |
||||||
|
|
||||||
|
1. Flash memory embedded in the ESP8266/ESP32 module |
||||||
|
2. SD device externally connected to the ESP8266/ESP32 module |
||||||
|
3. Other character devices |
||||||
|
|
||||||
|
You can specify the device type to save with the [**store**](acelements.md#store) attribute of AutoConenctFile, and it accepts the following values: |
||||||
|
|
||||||
|
- Flash : `AC_File_FS` for the API parameter or `fs` for the JSON document |
||||||
|
- SD : `AC_File_SD` for the API parameter or `sd` for the JSON document |
||||||
|
- Other : `AC_File_Extern` for the API parameter or `extern` for the JSON document |
||||||
|
|
||||||
|
The substance of AC_File_FS (fs) is a SPIFFS file system implemented by the ESP8266/ESP32 core, and then AutoConnect uses the Global Instance **SPIFFS** to access SPIFFS. |
||||||
|
|
||||||
|
Also, the substance of AC_File_SD (sd) is a FAT file of Arduino SD library ported to the ESP8266/ESP32 core, and then AutoConnect uses the Global Instance **SD** to access SD. When saving to an external SD device, there are additional required parameters for the connection interface and is defined as the macro in AutoConnectDefs.h. |
||||||
|
|
||||||
|
```cpp |
||||||
|
#define AUTOCONNECT_SD_CS SS |
||||||
|
#define AUTOCONNECT_SD_SPEED 4000000 |
||||||
|
``` |
||||||
|
|
||||||
|
`AUTOCONNECT_SD_CS` defines which GPIO for the CS (Chip Select, or SS as Slave Select) pin. This definition is derived from pins_arduino.h, which is included in the Arduino core distribution. If you want to assign the CS pin to another GPIO, you need to change the macro definition of AutoConnectDefs.h. |
||||||
|
|
||||||
|
`AUTOCONNECT_SD_SPEED` defines SPI clock speed depending on the connected device. |
||||||
|
|
||||||
|
!!! info "Involves both the begin() and the end()" |
||||||
|
The built-in uploader executes the begin and end functions regardless of the sketch whence the file system of the device will terminate with the uploader termination. Therefore, to use the device in the sketch after uploading, you need to **restart it with the begin** function. |
||||||
|
|
||||||
|
## When it will be uploaded |
||||||
|
|
||||||
|
Upload handler will be launched by ESP8266WebServer/WebServer(as ESP32) library which is triggered by receiving an HTTP stream of POST BODY including file content. Its launching occurs before invoking the page handler. |
||||||
|
|
||||||
|
The following diagram illustrates the file uploading sequence: |
||||||
|
|
||||||
|
<img src="images/ac_upload_flow.svg"> |
||||||
|
|
||||||
|
At the time of the page handler behaves, the uploaded file already saved to the device, and the [member variables](acelements.md#name_3) of AutoConnectFile reflects the file name and transfer size. |
||||||
|
|
||||||
|
## The file name for the uploaded file |
||||||
|
|
||||||
|
AutoConnetFile saves the uploaded file with the file name you selected by `<input type="file">` tag on the browser. The file name used for uploading is stored in the AutoConnetFile's value member, which you can access after uploading. (i.e. In the handler of the destination page by the AutoConnectSubmit element.) You can not save it with a different name. It can be renamed after upload if you need to change the name. |
||||||
|
|
||||||
|
## Upload to a device other than Flash or SD |
||||||
|
|
||||||
|
You can output the file to any device using a custom uploader by specifying [**extern**](acjson.md#acfile) with the [store](acjson.md#acfile) attribute of [AutoConnectFile (or specifying [**AC_File_Extern**](acelements.md#store) for the store member variable) and can customize the uploader according to the need to upload files to other than Flash or SD. Implements your own uploader with inheriting the [**AutoConnectUploadHandler**](#upload-handler-base-class) class which is the base class of the upload handler. |
||||||
|
|
||||||
|
!!! note "It's not so difficult" |
||||||
|
Implementing the custom uploader requires a little knowledge of the c++ language. If you are less attuned to programming c++, you may find it difficult. But don't worry. You can make it in various situations by just modifying the sketch skeleton that appears at the end of this page. |
||||||
|
|
||||||
|
### <i class="fa fa-code"></i> Upload handler base class |
||||||
|
|
||||||
|
AutoConnectUploadHandler is a base class of upload handler and It has one public member function and three protected functions. |
||||||
|
|
||||||
|
#### <i class="fa fa-caret-right"></i> Constructor |
||||||
|
|
||||||
|
```cpp |
||||||
|
AutoConnectUploadHandler() |
||||||
|
``` |
||||||
|
|
||||||
|
#### <i class="fa fa-caret-right"></i> Member functions |
||||||
|
|
||||||
|
The **upload** public function is an entry point, the ESP8266WebServer (WebServer as ESP32) library will invoke the upload with each time of uploading content divided into chunks. |
||||||
|
|
||||||
|
Also, the **\_open**, **\_write** and **\_close** protected functions are actually responsible for saving files and are declared as pure virtual functions. A custom uploader class that inherits from the AutoConnectUploadHandler class need to implement these functions. |
||||||
|
|
||||||
|
The actual upload process is handled by the three private functions above, and then upload only invokes three functions according to the upload situation. In usually, there is no need to override the upload function in an inherited class. |
||||||
|
|
||||||
|
```cpp |
||||||
|
public virtual void upload(const String& requestUri, const HTTPUpload& upload) |
||||||
|
``` |
||||||
|
<dl class="apidl"> |
||||||
|
<dt>**Parameters**</dt> |
||||||
|
<dd><span class="apidef">requestUri</span><span class="apidesc">URI of upload request source.</span></dd> |
||||||
|
<dd><span class="apidef">upload</span><span class="apidesc">A data structure of the upload file as <b>HTTPUpload</b>. It is defined in the ESP8266WebServer (WebServer as ESP32) library as follows: |
||||||
|
|
||||||
|
```cpp |
||||||
|
typedef struct { |
||||||
|
HTTPUploadStatus status; |
||||||
|
String filename; |
||||||
|
String name; |
||||||
|
String type; |
||||||
|
size_t totalSize; |
||||||
|
size_t currentSize; |
||||||
|
size_t contentLength; |
||||||
|
uint8_t buf[HTTP_UPLOAD_BUFLEN]; |
||||||
|
} HTTPUpload; |
||||||
|
``` |
||||||
|
</span></dd> |
||||||
|
</dl> |
||||||
|
|
||||||
|
The upload handler needs to implement processing based on the enumeration value of HTTPUpload.status as **HTTPUploadStatus** enum type. HTTPUploadStatus enumeration is as follows: |
||||||
|
|
||||||
|
- **`UPLOAD_FILE_START`** : Invokes to the \_open. |
||||||
|
- **`UPLOAD_FILE_WRITE`** : Invokes to the \_write. |
||||||
|
- **`UPLOAD_FILE_END`** : Invokes to the \_close. |
||||||
|
- **`UPLOAD_FILE_ABORTED`** : Invokes to the \_close. |
||||||
|
|
||||||
|
The \_open function will be invoked when HTTPUploadStatus is **UPLOAD_FILE_START**. Usually, the implementation of an inherited class will open the file. |
||||||
|
|
||||||
|
```cpp |
||||||
|
protected virtual bool _open(const char* filename, const char* mode) = 0 |
||||||
|
``` |
||||||
|
<dl class="apidl"> |
||||||
|
<dt>**Parameters**</dt> |
||||||
|
<dd><span class="apidef">filename</span><span class="apidesc">Uploading file name.</span></dd> |
||||||
|
<dd><span class="apidef">mode</span><span class="apidesc">An indicator for the file access mode, a "w" for writing.</span></dd> |
||||||
|
<dt>**Return value**</dt> |
||||||
|
<dd><span class="apidef">true</span><span class="apidesc">File open successful.</span></dd> |
||||||
|
<dd><span class="apidef">false</span><span class="apidesc">Failed to open.</span></dd> |
||||||
|
</dl> |
||||||
|
|
||||||
|
The \_write function will be invoked when HTTPUploadStatus is **UPLOAD_FILE_WRITE**. The content of the upload file is divided and the \_write will be invoked in multiple times. Usually, the implementation of an inherited class will write data. |
||||||
|
|
||||||
|
```cpp |
||||||
|
protected virtual size_t _write(const uint8_t *buf, const size_t size))= 0 |
||||||
|
``` |
||||||
|
<dl class="apidl"> |
||||||
|
<dt>**Parameters**</dt> |
||||||
|
<dd><span class="apidef">buf</span><span class="apidesc">File content block.</span></dd> |
||||||
|
<dd><span class="apidef">size</span><span class="apidesc">File block size to write.</span></dd> |
||||||
|
<dt>**Return value**</dt> |
||||||
|
<dd>Size written.</dd> |
||||||
|
</dl> |
||||||
|
|
||||||
|
The \_close function will be invoked when HTTPUploadStatus is **UPLOAD_FILE_END** or **UPLOAD_FILE_ABORTED**. Usually, the implementation of an inherited class will close the file. |
||||||
|
|
||||||
|
```cpp |
||||||
|
protected virtual void _close(void) = 0 |
||||||
|
``` |
||||||
|
|
||||||
|
For reference, the following AutoConnectUploadFS class is an implementation of AutoConnect built-in uploader and inherits from AutoConnectUploadHandler. |
||||||
|
|
||||||
|
```cpp |
||||||
|
class AutoConnectUploadFS : public AutoConnectUploadHandler { |
||||||
|
public: |
||||||
|
explicit AutoConnectUploadFS(SPIFFST& media) : _media(&media) {} |
||||||
|
~AutoConnectUploadFS() { _close(); } |
||||||
|
|
||||||
|
protected: |
||||||
|
bool _open(const char* filename, const char* mode) override { |
||||||
|
if (_media->begin()) { |
||||||
|
_file = _media->open(filename, mode); |
||||||
|
return _file != false; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
size_t _write(const uint8_t* buf, const size_t size) override { |
||||||
|
if (_file) |
||||||
|
return _file.write(buf, size); |
||||||
|
else |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
void _close(void) override { |
||||||
|
if (_file) |
||||||
|
_file.close(); |
||||||
|
_media->end(); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
SPIFFST* _media; |
||||||
|
SPIFileT _file; |
||||||
|
}; |
||||||
|
``` |
||||||
|
|
||||||
|
### <i class="fa fa-code"></i> Register custom upload handler |
||||||
|
|
||||||
|
In order to upload a file by the custom uploader, it is necessary to register it to the custom Web page beforehand. To register a custom uploader, specify the custom uploader class name in the template argument of the [AutoConnectAux::onUpload](apiaux.md#onupload) function and invokes it. |
||||||
|
|
||||||
|
```cpp |
||||||
|
void AutoConnectAux::onUpload<T>(T& uploadClass) |
||||||
|
``` |
||||||
|
<dl class="apidl"> |
||||||
|
<dt>**Parameters**</dt> |
||||||
|
<dd><span class="apidef">T</span><span class="apidesc">Specifies a class name of the custom uploader. This class name is a class that you implemented by inheriting AutoConnectUploadHandler for custom upload.</span></dd> |
||||||
|
<dd><span class="apidef">uploadClass</span><span class="apidesc">Specifies the custom upload class instance.</span></dd> |
||||||
|
</dl> |
||||||
|
|
||||||
|
The rough structure of the sketches that completed these implementations will be as follows: |
||||||
|
|
||||||
|
```cpp |
||||||
|
#include <ESP8266WiFi.h> |
||||||
|
#include <ESP8266WebServer.h> |
||||||
|
#include <AutoConnect.h> |
||||||
|
|
||||||
|
static const char PAGE_UPLOAD[] PROGMEM = R"( |
||||||
|
{ |
||||||
|
"uri": "/", |
||||||
|
"title": "Upload", |
||||||
|
"menu": true, |
||||||
|
"element": [ |
||||||
|
{ "name":"caption", "type":"ACText", "value":"<h2>File uploading platform<h2>" }, |
||||||
|
{ "name":"upload_file", "type":"ACFile", "label":"Select file: ", "store":"extern" }, |
||||||
|
{ "name":"upload", "type":"ACSubmit", "value":"UPLOAD", "uri":"/upload" } |
||||||
|
] |
||||||
|
} |
||||||
|
)"; |
||||||
|
|
||||||
|
static const char PAGE_RECEIVED[] PROGMEM = R"( |
||||||
|
{ |
||||||
|
"uri": "/upload", |
||||||
|
"title": "Upload ended", |
||||||
|
"menu": false, |
||||||
|
"element": [ |
||||||
|
{ "name":"caption", "type":"ACText", "value":"<h2>File uploading ended<h2>" } |
||||||
|
] |
||||||
|
} |
||||||
|
)"; |
||||||
|
|
||||||
|
// Custom upload handler class |
||||||
|
class CustomUploader : public AutoConnectUploadHandler { |
||||||
|
public: |
||||||
|
CustomUploader() {} |
||||||
|
~CustomUploader() {} |
||||||
|
|
||||||
|
protected: |
||||||
|
bool _open(const char* filename, const char* mode) override; |
||||||
|
size_t _write(const uint8_t *buf, const size_t size) override; |
||||||
|
void _close(void) override; |
||||||
|
}; |
||||||
|
|
||||||
|
// _open for custom open |
||||||
|
bool CustomUploader::_open(const char* filename, const char* mode) { |
||||||
|
// Here, an implementation for the open file. |
||||||
|
} |
||||||
|
|
||||||
|
// _open for custom write |
||||||
|
size_t CustomUploader::_write(const uint8_t *buf, const size_t size) { |
||||||
|
// Here, an implementation for the writing the file data. |
||||||
|
} |
||||||
|
|
||||||
|
// _open for custom close |
||||||
|
void CustomUploader::_close(void) { |
||||||
|
// Here, an implementation for the close file. |
||||||
|
} |
||||||
|
|
||||||
|
AutoConnect portal; |
||||||
|
AutoConnectAux uploadPage; |
||||||
|
AutoConnectAux receivePage; |
||||||
|
CustomUploader uploader; // Declare the custom uploader |
||||||
|
|
||||||
|
void setup() { |
||||||
|
uploadPage.load(PAGE_UPLOAD); |
||||||
|
receivePage.load(PAGE_RECEIVED); |
||||||
|
portal.join({ uploadPage, receivePage }); |
||||||
|
receivePage.onUpload<CustomUploader>(uploader); // Register the custom uploader |
||||||
|
portal.begin(); |
||||||
|
} |
||||||
|
|
||||||
|
void loop() { |
||||||
|
portal.handleClient(); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
!!! note "Don't forget to specify the store" |
||||||
|
When using a custom uploader, remember to specify the **extern** for the store attribute of AutoConnectFile. |
||||||
|
|
||||||
|
<script> |
||||||
|
window.onload = function() { |
||||||
|
Gifffer(); |
||||||
|
}; |
||||||
|
</script> |
@ -0,0 +1,142 @@ |
|||||||
|
## Saved credential in EEPROM |
||||||
|
|
||||||
|
AutoConnect stores the established WiFi connection in the EEPROM of the ESP8266/ESP32 module and equips the class to access it from the sketch. You can read, write or erase the credentials using this class individually. It's [**AutoConnectCredential**](#autoconnectcredential) class which provides the access method to the saved credentials in EEPROM.[^1] |
||||||
|
|
||||||
|
[^1]:An example using AutoConnectCredential is provided as [an example](https://github.com/Hieromon/AutoConnect/blob/master/examples/Credential/Credential.ino) of a library sketch to delete saved credentials. |
||||||
|
|
||||||
|
## AutoConnectCredential |
||||||
|
|
||||||
|
### <i class="fa fa-code"></i> Include header |
||||||
|
|
||||||
|
```cpp |
||||||
|
#include <AutoConnectCredential.h> |
||||||
|
``` |
||||||
|
|
||||||
|
### <i class="fa fa-code"></i> Constructors |
||||||
|
|
||||||
|
```cpp |
||||||
|
AutoConnectCredential(); |
||||||
|
``` |
||||||
|
|
||||||
|
AutoConnectCredential default constructor. The default offset value is 0. If the offset value is 0, the credential area starts from the top of the EEPROM. AutoConnect sometimes overwrites data when using this area with user sketch. |
||||||
|
|
||||||
|
```cpp |
||||||
|
AutoConnectCredential(uint16_t offset); |
||||||
|
``` |
||||||
|
<dl class="apidl"> |
||||||
|
<dt>**Parameter**</dt> |
||||||
|
<dd><span class="apidef">offset</span><span class="apidesc">Species offset from the top of the EEPROM for the credential area together. The offset value is from 0 to the flash sector size.</span></dd> |
||||||
|
</dl> |
||||||
|
|
||||||
|
### <i class="fa fa-code"></i> Public member functions |
||||||
|
|
||||||
|
#### <i class="fa fa-caret-right"></i> entries |
||||||
|
|
||||||
|
```cpp |
||||||
|
uint8_t entries(void) |
||||||
|
``` |
||||||
|
|
||||||
|
Returns number of entries as contained credentials. |
||||||
|
<dl class="apidl"> |
||||||
|
<dt>**Return value**</dt> |
||||||
|
<dd>Number of entries as contained credentials.</dd> |
||||||
|
</dl> |
||||||
|
|
||||||
|
#### <i class="fa fa-caret-right"></i> load |
||||||
|
|
||||||
|
```cpp |
||||||
|
int8_t load(const char* ssid, struct station_config* config) |
||||||
|
``` |
||||||
|
|
||||||
|
Load a credential entry and store to **config**. |
||||||
|
<dl class="apidl"> |
||||||
|
<dt>**Parameters**</dt> |
||||||
|
<dd><span class="apidef">ssid</span><span class="apidesc">SSID to be loaded.</span></dd> |
||||||
|
<dd><span class="apidef">config</span><span class="apidesc">station_config</span></dd> |
||||||
|
<dt>**Return value**</dt> |
||||||
|
<dd>Save the specified SSID's credential entry to station_config pointed to by the parameter as **config**. -1 is returned if the SSID is not saved. </dd> |
||||||
|
</dl> |
||||||
|
|
||||||
|
#### <i class="fa fa-caret-right"></i> load |
||||||
|
|
||||||
|
```cpp |
||||||
|
bool load(int8_t entry, struct station_config* config) |
||||||
|
``` |
||||||
|
|
||||||
|
Load a credential entry and store to **config**. |
||||||
|
<dl class="apidl"> |
||||||
|
<dt>**Parameters**</dt> |
||||||
|
<dd><span class="apidef">entry</span><span class="apidesc">Specifies the index number based 0 to be loaded.</span></dd> |
||||||
|
<dd><span class="apidef">config</span><span class="apidesc">station_config</span></dd> |
||||||
|
<dt>**Return value**</dt> |
||||||
|
<dd>Save the specified credential entry to station_config pointed to by the parameter as **config**. -1 is returned if specified number is not saved. </dd> |
||||||
|
</dl> |
||||||
|
|
||||||
|
#### <i class="fa fa-caret-right"></i> save |
||||||
|
|
||||||
|
```cpp |
||||||
|
bool save(const struct station_config* config) |
||||||
|
``` |
||||||
|
|
||||||
|
Save a credentail entry. |
||||||
|
<dl class="apidl"> |
||||||
|
<dt>**Parameter**</dt> |
||||||
|
<dd><span class="apidef">config</span><span class="apidesc">station_config to be saved.</span></dd> |
||||||
|
<dt>**Return value**</dt> |
||||||
|
<dd><span class="apidef">true</span><span class="apidesc">Successfully saved.</span></dd> |
||||||
|
<dd><span class="apidef">false</span><span class="apidesc">Failed to save.</span></dd> |
||||||
|
</dl> |
||||||
|
|
||||||
|
#### <i class="fa fa-caret-right"></i> del |
||||||
|
|
||||||
|
```cpp |
||||||
|
bool del(const char* ssid) |
||||||
|
``` |
||||||
|
|
||||||
|
Delete a credential the specified SSID. |
||||||
|
<dl class="apidl"> |
||||||
|
<dt>**Parameter**</dt> |
||||||
|
<dd><span class="apidef">ssid</span><span class="apidesc">SSID to be deleted.</span></dd> |
||||||
|
<dt>**Return value**</dt> |
||||||
|
<dd><span class="apidef">true</span><span class="apidesc">Successfully deleted.</span></dd> |
||||||
|
<dd><span class="apidef">false</span><span class="apidesc">Failed to delete.</span></dd> |
||||||
|
</dl> |
||||||
|
|
||||||
|
## The data structures |
||||||
|
|
||||||
|
### <i class="fa fa-code"></i> station_config |
||||||
|
|
||||||
|
A structure is included in the ESP8266 SDK. You can use it in the sketch like as follows: |
||||||
|
|
||||||
|
```cpp |
||||||
|
extern "C" { |
||||||
|
#include <user_interface.h> |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
```cpp |
||||||
|
struct station_config { |
||||||
|
uint8 ssid[32]; |
||||||
|
uint8 password[64]; |
||||||
|
uint8 bssid_set; |
||||||
|
uint8 bssid[6]; |
||||||
|
}; |
||||||
|
``` |
||||||
|
|
||||||
|
### <i class="fa fa-code"></i> The credential entry |
||||||
|
|
||||||
|
A data structure of the credential saving area in EEPROM as the below. [^2] |
||||||
|
|
||||||
|
[^2]: |
||||||
|
There may be 0xff as an invalid data in the credential saving area. The 0xff area would be reused. |
||||||
|
|
||||||
|
| Byte offset | Length | Value | |
||||||
|
|-------------|----------|---------------------------------------------------------------------| |
||||||
|
| 0 | 8 | AC_CREDT | |
||||||
|
| 8 | 1 | Number of contained entries (uint8_t) | |
||||||
|
| 9 | 2 | Container size, excluding size of AC_CREDT and size of the number of entries(width for uint16_t type). | |
||||||
|
| 11 | variable | SSID terminated by 0x00. Max length is 32 bytes. | |
||||||
|
| variable | variable | Password plain text terminated by 0x00. Max length is 64 bytes. | |
||||||
|
| variable | 6 | BSSID | |
||||||
|
| variable | | Contained the next entries. (Continuation SSID+Password+BSSID) | |
||||||
|
| variable | 1 | 0x00. End of container. | |
After Width: | Height: | Size: 120 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 179 KiB |
@ -0,0 +1,416 @@ |
|||||||
|
/**
|
||||||
|
* Implementation of template functions of AutoConnect and AutoConnectAux.
|
||||||
|
* This implementation instantiates completely the void AutoConnectElement |
||||||
|
* as each type and also absorbs interface differences due to ArduinoJson |
||||||
|
* version differences.
|
||||||
|
* @file AutoConnectAuxImpl.h |
||||||
|
* @author hieromon@gmail.com |
||||||
|
* @version 0.9.8 |
||||||
|
* @date 2019-03-21 |
||||||
|
* @copyright MIT license. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef _AUTOCONNECTAUXIMPL_H_ |
||||||
|
#define _AUTOCONNECTAUXIMPL_H_ |
||||||
|
|
||||||
|
#include "AutoConnectDefs.h" |
||||||
|
|
||||||
|
#ifndef AUTOCONNECT_USE_JSON |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectElementBasis element. |
||||||
|
* @param name an element name. |
||||||
|
* @return A reference of AutoConnectElement class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectElementBasis& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
return *(reinterpret_cast<AutoConnectElementBasis*>(elm)); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectElementBasis&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectButtonBasis element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectButton class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectButtonBasis& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_Button) |
||||||
|
return *(reinterpret_cast<AutoConnectButtonBasis*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectButtonBasis&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectCheckboxBasis element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectCheckbox class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectCheckboxBasis& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_Checkbox) |
||||||
|
return *(reinterpret_cast<AutoConnectCheckboxBasis*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectCheckboxBasis&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectFileBasis element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectFile class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectFileBasis& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_File) |
||||||
|
return *(reinterpret_cast<AutoConnectFileBasis*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectFileBasis&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectInputBasis element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectInput class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectInputBasis& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_Input) |
||||||
|
return *(reinterpret_cast<AutoConnectInputBasis*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectInputBasis&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectRadioBasis element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectRadio class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectRadioBasis& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_Radio) |
||||||
|
return *(reinterpret_cast<AutoConnectRadioBasis*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectRadioBasis&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectSelectBasis element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectSelect class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectSelectBasis& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_Select) |
||||||
|
return *(reinterpret_cast<AutoConnectSelectBasis*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectSelectBasis&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectSubmitBasis element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectSubmit class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectSubmitBasis& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_Submit) |
||||||
|
return *(reinterpret_cast<AutoConnectSubmitBasis*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectSubmitBasis&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectTextBasis element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectText class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectTextBasis& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_Text) |
||||||
|
return *(reinterpret_cast<AutoConnectTextBasis*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectTextBasis&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
#else |
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse and load a JSON document which marks up multiple custom web |
||||||
|
* pages. The compiler instantiates this template according to the stored |
||||||
|
* data type that contains the JSON document. |
||||||
|
* This template also generates different parsing function calls |
||||||
|
* depending on the ArduinoJson version. |
||||||
|
* @param T An object type of the JSON document which must be a |
||||||
|
* passable object to ArduinoJson. |
||||||
|
* @param in An instance of a source JSON document to load. |
||||||
|
*/ |
||||||
|
template<typename T> |
||||||
|
bool AutoConnect::_parseJson(T in) { |
||||||
|
ArduinoJsonBuffer jsonBuffer(AUTOCONNECT_JSONBUFFER_PRIMITIVE_SIZE); |
||||||
|
JsonVariant jv; |
||||||
|
#if ARDUINOJSON_VERSION_MAJOR<=5 |
||||||
|
jv = jsonBuffer.parse(in); |
||||||
|
if (!jv.success()) { |
||||||
|
AC_DBG("JSON parse error\n"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
#else |
||||||
|
DeserializationError err = deserializeJson(jsonBuffer, in); |
||||||
|
if (err) { |
||||||
|
AC_DBG("Deserialize error:%s\n", err.c_str()); |
||||||
|
return false; |
||||||
|
} |
||||||
|
jv = jsonBuffer.as<JsonVariant>(); |
||||||
|
#endif |
||||||
|
return _load(jv); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse and load a JSON document which marks up a custom web page. |
||||||
|
* The compiler instantiates this template according to the stored data |
||||||
|
* type that contains the JSON document. |
||||||
|
* This template also generates different parsing function calls |
||||||
|
* depending on the ArduinoJson version. |
||||||
|
* @param T An object type of the JSON document which must be a |
||||||
|
* passable object to ArduinoJson. |
||||||
|
* @param in An instance of a source JSON document to load. |
||||||
|
*/ |
||||||
|
template<typename T> |
||||||
|
bool AutoConnectAux::_parseJson(T in) { |
||||||
|
ArduinoJsonBuffer jsonBuffer(AUTOCONNECT_JSONBUFFER_PRIMITIVE_SIZE); |
||||||
|
#if ARDUINOJSON_VERSION_MAJOR<=5 |
||||||
|
JsonObject& jb = jsonBuffer.parseObject(in); |
||||||
|
if (!jb.success()) { |
||||||
|
AC_DBG("JSON parse error\n"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
#else |
||||||
|
DeserializationError err = deserializeJson(jsonBuffer, in); |
||||||
|
if (err) { |
||||||
|
AC_DBG("Deserialize:%s\n", err.c_str()); |
||||||
|
return false; |
||||||
|
} |
||||||
|
JsonObject jb = jsonBuffer.as<JsonObject>(); |
||||||
|
#endif |
||||||
|
return _load(jb); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse and load a JSON document which declares one of the AutoConnectElement. |
||||||
|
* The compiler instantiates this template according to the stored data |
||||||
|
* type that contains the JSON document. |
||||||
|
* This template also generates different parsing function calls |
||||||
|
* depending on the ArduinoJson version. |
||||||
|
* @param T An object type of the JSON document which must be a |
||||||
|
* passable object to ArduinoJson. |
||||||
|
* @param in An instance of a source JSON document to load. |
||||||
|
*/ |
||||||
|
template<typename T> |
||||||
|
bool AutoConnectAux::_parseElement(T in, const String& name) { |
||||||
|
ArduinoJsonBuffer jsonBuffer(AUTOCONNECT_JSONBUFFER_PRIMITIVE_SIZE); |
||||||
|
JsonVariant jb; |
||||||
|
#if ARDUINOJSON_VERSION_MAJOR<=5 |
||||||
|
jb = jsonBuffer.parse(in); |
||||||
|
if (!jb.success()) { |
||||||
|
AC_DBG("JSON parse error\n"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
#else |
||||||
|
DeserializationError err = deserializeJson(jsonBuffer, in); |
||||||
|
if (err) { |
||||||
|
AC_DBG("Deserialize:%s\n", err.c_str()); |
||||||
|
return false; |
||||||
|
} |
||||||
|
jb = jsonBuffer.as<JsonVariant>(); |
||||||
|
#endif |
||||||
|
return _loadElement(jb, name); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectElementJson element. |
||||||
|
* @param name an element name. |
||||||
|
* @return A reference of AutoConnectElement class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectElementJson& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
return *(reinterpret_cast<AutoConnectElementJson*>(elm)); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectElementJson&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectButtonJson element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectButton class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectButtonJson& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_Button) |
||||||
|
return *(reinterpret_cast<AutoConnectButtonJson*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectButtonJson&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectCheckboxJson element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectCheckbox class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectCheckboxJson& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_Checkbox) |
||||||
|
return *(reinterpret_cast<AutoConnectCheckboxJson*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectCheckboxJson&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectFile element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectFile class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectFileJson& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_File) |
||||||
|
return *(reinterpret_cast<AutoConnectFileJson*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectFileJson&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectInputJson element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectInput class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectInputJson& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_Input) |
||||||
|
return *(reinterpret_cast<AutoConnectInputJson*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectInputJson&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectRadioJson element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectRadio class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectRadioJson& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_Radio) |
||||||
|
return *(reinterpret_cast<AutoConnectRadioJson*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectRadioJson&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectSelectJson element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectSelect class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectSelectJson& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_Select) |
||||||
|
return *(reinterpret_cast<AutoConnectSelectJson*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectSelectJson&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectSubmitJson element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectSubmit class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectSubmitJson& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_Submit) |
||||||
|
return *(reinterpret_cast<AutoConnectSubmitJson*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectSubmitJson&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AutoConnectTextJson element. |
||||||
|
* @param name An element name. |
||||||
|
* @return A reference of AutoConnectText class. |
||||||
|
*/ |
||||||
|
template<> |
||||||
|
AutoConnectTextJson& AutoConnectAux::getElement(const String& name) { |
||||||
|
AutoConnectElement* elm = getElement(name); |
||||||
|
if (elm) { |
||||||
|
if (elm->typeOf() == AC_Text) |
||||||
|
return *(reinterpret_cast<AutoConnectTextJson*>(elm)); |
||||||
|
else |
||||||
|
AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); |
||||||
|
} |
||||||
|
return reinterpret_cast<AutoConnectTextJson&>(_nullElement()); |
||||||
|
} |
||||||
|
|
||||||
|
#endif // !AUTOCONNECT_USE_JSON
|
||||||
|
|
||||||
|
#endif // !_AUTOCONNECTAUXIMPL_H_
|
@ -0,0 +1,65 @@ |
|||||||
|
/**
|
||||||
|
* AutoConnect proper menu label constant definition. |
||||||
|
* @file AutoConnectLabels.h |
||||||
|
* @author hieromon@gmail.com |
||||||
|
* @version 0.9.8 |
||||||
|
* @date 2019-03-11 |
||||||
|
* @copyright MIT license. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef _AUTOCONNECTLABELS_H_ |
||||||
|
#define _AUTOCONNECTLABELS_H_ |
||||||
|
|
||||||
|
/**
|
||||||
|
* The upper row of each of the following definition items is the |
||||||
|
* default value. The lower row is an alternative label string as |
||||||
|
* a sample and can be changed you wish. |
||||||
|
* |
||||||
|
* Notes: |
||||||
|
* You can find some tokens for the PageBuilder if you parse |
||||||
|
* AutoConnectPage.cpp. Some of the tokens are valid at the time |
||||||
|
* the AutoConnect menu will generate. For example, the token |
||||||
|
* `{{CUR_SSID}}` returns the SSID of the currently participating |
||||||
|
* AP by AutoConnect::_token_CURRENT_SSID function. |
||||||
|
* You can use these tokens to display dynamic menus showing the |
||||||
|
* current situation, but you need to know the internal structure |
||||||
|
* of AutoConnect in order to display the appropriate menu. |
||||||
|
*/ |
||||||
|
|
||||||
|
// Menu item: Configure new AP
|
||||||
|
#ifndef AUTOCONNECT_MENULABEL_CONFIGNEW |
||||||
|
#define AUTOCONNECT_MENULABEL_CONFIGNEW "Configure new AP" |
||||||
|
//#define AUTOCONNECT_MENULABEL_CONFIGNEW "Establish a new AP"
|
||||||
|
#endif // !AUTOCONNECT_MENULABEL_CONFIGNEW
|
||||||
|
|
||||||
|
// Menu item: Open SSIDs
|
||||||
|
#ifndef AUTOCONNECT_MENULABEL_OPENSSIDS |
||||||
|
#define AUTOCONNECT_MENULABEL_OPENSSIDS "Open SSIDs" |
||||||
|
//#define AUTOCONNECT_MENULABEL_OPENSSIDS "Open credentials"
|
||||||
|
#endif // !AUTOCONNECT_MENULABEL_OPENSSIDS
|
||||||
|
|
||||||
|
// Menu item: Disconnect
|
||||||
|
#ifndef AUTOCONNECT_MENULABEL_DISCONNECT |
||||||
|
#define AUTOCONNECT_MENULABEL_DISCONNECT "Disconnect" |
||||||
|
//#define AUTOCONNECT_MENULABEL_DISCONNECT "Leave {{CUR_SSID}}"
|
||||||
|
#endif // !AUTOCONNECT_MENULABEL_DISCONNECT
|
||||||
|
|
||||||
|
// Menu item: Reset...
|
||||||
|
#ifndef AUTOCONNECT_MENULABEL_RESET |
||||||
|
#define AUTOCONNECT_MENULABEL_RESET "Reset..." |
||||||
|
//#define AUTOCONNECT_MENULABEL_RESET "Reboot..."
|
||||||
|
#endif // !AUTOCONNECT_MENULABEL_RESET
|
||||||
|
|
||||||
|
// Menu item: HOME
|
||||||
|
#ifndef AUTOCONNECT_MENULABEL_HOME |
||||||
|
#define AUTOCONNECT_MENULABEL_HOME "HOME" |
||||||
|
//#define AUTOCONNECT_MENULABEL_HOME "Main"
|
||||||
|
#endif // !AUTOCONNECT_MENULABEL_HOME
|
||||||
|
|
||||||
|
// Button label: RESET
|
||||||
|
#ifndef AUTOCONNECT_BUTTONLABEL_RESET |
||||||
|
#define AUTOCONNECT_BUTTONLABEL_RESET "RESET" |
||||||
|
//#define AUTOCONNECT_BUTTONLABEL_RESET "Reboot"
|
||||||
|
#endif // !AUTOCONNECT_BUTTONLABEL_RESET
|
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,38 @@ |
|||||||
|
/**
|
||||||
|
* The upload wrapper base class definition and the default up-loader |
||||||
|
* class declarations. |
||||||
|
* @file AutoConnectUpload.h |
||||||
|
* @author hieromon@gmail.com |
||||||
|
* @version 0.9.8 |
||||||
|
* @date 2019-03-19 |
||||||
|
* @copyright MIT license. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef _AUTOCONNECTUPLOAD_H_ |
||||||
|
#define _AUTOCONNECTUPLOAD_H_ |
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_ESP8266) |
||||||
|
#include <ESP8266WiFi.h> |
||||||
|
#include <ESP8266WebServer.h> |
||||||
|
#elif defined(ARDUINO_ARCH_ESP32) |
||||||
|
#include <WiFi.h> |
||||||
|
#include <WebServer.h> |
||||||
|
#endif |
||||||
|
|
||||||
|
/**
|
||||||
|
* Uploader base class. This class is a wrapper for the AutoConnectUpload |
||||||
|
* class, and only the upload member function is implemented. |
||||||
|
*/ |
||||||
|
class AutoConnectUploadHandler { |
||||||
|
public: |
||||||
|
explicit AutoConnectUploadHandler() {} |
||||||
|
virtual ~AutoConnectUploadHandler() {} |
||||||
|
virtual void upload(const String& requestUri, const HTTPUpload& upload); |
||||||
|
|
||||||
|
protected: |
||||||
|
virtual bool _open(const char* filename, const char* mode) = 0; |
||||||
|
virtual size_t _write(const uint8_t *buf, const size_t size) = 0; |
||||||
|
virtual void _close(void) = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // !_AUTOCONNECTUPLOAD_H_
|
@ -0,0 +1,145 @@ |
|||||||
|
/**
|
||||||
|
* The default upload handler implementation. |
||||||
|
* @file AutoConnectUploadImpl.h |
||||||
|
* @author hieromon@gmail.com |
||||||
|
* @version 0.9.8 |
||||||
|
* @date 2019-03-19 |
||||||
|
* @copyright MIT license. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef _AUTOCONNECTUPLOADIMPL_H_ |
||||||
|
#define _AUTOCONNECTUPLOADIMPL_H_ |
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_ESP8266) |
||||||
|
#include <ESP8266WiFi.h> |
||||||
|
#elif defined(ARDUINO_ARCH_ESP32) |
||||||
|
#include <WiFi.h> |
||||||
|
#include <SPIFFS.h> |
||||||
|
#endif |
||||||
|
#include <SPI.h> |
||||||
|
#include <SD.h> |
||||||
|
#define FS_NO_GLOBALS |
||||||
|
#include <FS.h> |
||||||
|
|
||||||
|
// Types branching to be code commonly for the file system classes with
|
||||||
|
// ESP8266 and ESP32.
|
||||||
|
#if defined(ARDUINO_ARCH_ESP8266) |
||||||
|
typedef fs::FS SPIFFST; // SPIFFS:File system class
|
||||||
|
typedef fs::File SPIFileT; // SPIFFS:File class
|
||||||
|
typedef SDClass SDClassT; // SD:File system class
|
||||||
|
typedef File SDFileT; // SD:File class
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP32) |
||||||
|
typedef fs::SPIFFSFS SPIFFST; |
||||||
|
typedef fs::File SPIFileT; |
||||||
|
typedef fs::SDFS SDClassT; |
||||||
|
typedef SDFile SDFileT; |
||||||
|
#endif |
||||||
|
|
||||||
|
#include "AutoConnectDefs.h" |
||||||
|
#include "AutoConnectUpload.h" |
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the default upload process depending on the upload status. |
||||||
|
* This handler function supports the status of UPLOAD_FILE_START, |
||||||
|
* UPLOAD_FILE_WRITE, UPLOAD_FILE_END and calls open, write and |
||||||
|
* close processing respectively. |
||||||
|
* @param requestUri A reference to the upload request uri. |
||||||
|
* @param upload A reference of HTTPUpload entity. |
||||||
|
*/ |
||||||
|
void AutoConnectUploadHandler::upload(const String& requestUri, const HTTPUpload& upload) { |
||||||
|
AC_UNUSED(requestUri); |
||||||
|
switch (upload.status) { |
||||||
|
case UPLOAD_FILE_START: { |
||||||
|
String absFilename = "/" + upload.filename; |
||||||
|
(void)_open(absFilename.c_str(), "w"); |
||||||
|
break; |
||||||
|
} |
||||||
|
case UPLOAD_FILE_WRITE: |
||||||
|
(void)_write(upload.buf, (const size_t)upload.currentSize); |
||||||
|
break; |
||||||
|
case UPLOAD_FILE_ABORTED: |
||||||
|
case UPLOAD_FILE_END: |
||||||
|
_close(); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Default handler for uploading to the standard SPIFFS class embedded in the core.
|
||||||
|
class AutoConnectUploadFS : public AutoConnectUploadHandler { |
||||||
|
public: |
||||||
|
explicit AutoConnectUploadFS(SPIFFST& media) : _media(&media) {} |
||||||
|
~AutoConnectUploadFS() { _close(); } |
||||||
|
|
||||||
|
protected: |
||||||
|
bool _open(const char* filename, const char* mode) override { |
||||||
|
#if defined(ARDUINO_ARCH_ESP8266) |
||||||
|
if (_media->begin()) { |
||||||
|
#elif defined(ARDUINO_ARCH_ESP32) |
||||||
|
if (_media->begin(true)) { |
||||||
|
#endif |
||||||
|
_file = _media->open(filename, mode); |
||||||
|
return _file != false;
|
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
size_t _write(const uint8_t* buf, const size_t size) override { |
||||||
|
if (_file) |
||||||
|
return _file.write(buf, size); |
||||||
|
else |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
void _close(void) override { |
||||||
|
if (_file) |
||||||
|
_file.close(); |
||||||
|
_media->end(); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
SPIFFST* _media; |
||||||
|
SPIFileT _file;
|
||||||
|
}; |
||||||
|
|
||||||
|
// Default handler for uploading to the standard SD class embedded in the core.
|
||||||
|
class AutoConnectUploadSD : public AutoConnectUploadHandler { |
||||||
|
public: |
||||||
|
explicit AutoConnectUploadSD(SDClassT& media, const uint8_t cs = AUTOCONNECT_SD_CS, const uint32_t speed = AUTOCONNECT_SD_SPEED) : _media(&media), _cs(cs), _speed(speed) {} |
||||||
|
~AutoConnectUploadSD() { _close(); } |
||||||
|
|
||||||
|
protected: |
||||||
|
bool _open(const char* filename, const char* mode) override { |
||||||
|
#if defined(ARDUINO_ARCH_ESP8266) |
||||||
|
if (_media->begin(_cs, _speed)) { |
||||||
|
uint8_t oflag = *mode == 'w' ? FILE_WRITE : FILE_READ; |
||||||
|
#elif defined(ARDUINO_ARCH_ESP32) |
||||||
|
if (_media->begin(_cs, SPI, _speed)) { |
||||||
|
const char* oflag = mode; |
||||||
|
#endif |
||||||
|
_file = _media->open(filename, oflag); |
||||||
|
return _file != false; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
size_t _write(const uint8_t* buf, const size_t size) override { |
||||||
|
if (_file) |
||||||
|
return _file.write(buf, size); |
||||||
|
else |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
void _close(void) override { |
||||||
|
if (_file) |
||||||
|
_file.close(); |
||||||
|
_media->end(); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
SDClassT* _media; |
||||||
|
SDFileT _file; |
||||||
|
uint8_t _cs; |
||||||
|
uint8_t _speed; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // !_AUTOCONNECTUPLOADIMPL_H_
|
Loading…
Reference in new issue