ESP8266の小物を作っていると、WebServer機能でのパラメータ登録機能があると
同じ小物を複数個運用するのに、設定や確認が楽だろうなぁと感じています。
今回はSPIFFSにあるhtmlファイルを読込んで、inifileに従った内容に更新するクラスを作成しました。
=>xmlでやれば良かったと何気に後悔中です。
これだけだとイマイチなのですが、ESP8266WebServer.hを使うと良い感じになるのでは? と期待して作っています。
ESP8266環境で必要なリソース
SPIFFS / FS等のファイルアクセスの環境
inifile.h 私が作成したヤツです。
機能
1. 入力項目 input type="text" の value をinifileの登録値に変更する
2. パスワード入力項目 input type="password" の value をinifileの登録値に変更する
3. ラジオボタンの初期値をinifileの登録値側にします。
4. レンジ入力の初期値をinifileのものに置き換えます。
5. コンボ入力の初期値をinifileのものに置き換えます。
使い方
ソースはこんな風にします。
# include <inifile.h>
const char *iniFileName = "/setup.ini"; // Inifileのファイル名
const char *iniHeader = "SETUP";
iniFiles ini(iniFileName);
# include <WebServerToolHtml.h>
//==
void setup() {
Serial.begin(115200); Serial.flush(); delay(1000);
Serial.println("program start");
if( SPIFFS.begin() )
Serial.println("SPIFFS Initialize....ok");
else
{
Serial.println("SPIFFS Initialization...failed");
return;
}
WebServerToolHtml.readHtmlFile( "/index.html" );
Serial.println( WebServerToolHtml.buffer() );
WebServerToolHtml.release();
}
void loop() {
}
ESP8266/ESP32のSPIFFSに、このsetup.iniファイルをコピーします。
[SETUP]
SSID=TEST_SSID
PASSWORD=TEST_PASSWORD
switch=on
range=22.2
sensor=HTU21D
*
ESP8266/ESP32のSPIFFSに、このhtmlファイルをコピーします。 注) '<' を '<'に変更してあるので戻す必要があります。
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<form name='SETUP' action=SETUP method='post'>
<p>SWITCH</p>
<p>SSID:<input type="text" name="SSID" size="30" maxlength="30" value="SAMPLESSID"></p>
<p>PASS:<input type="password" name="PASSWORD" size="30" maxlength="30" value="SAMPLEPASSWORD"></p>
<p>
<input type="radio" name="switch" value="on" >ON
<input type="radio" name="switch" value="off">OFF
</p>
<p><input type="range" name="volume1" value="1" min="-10.0" max="29.9" step="0.1"></p>
<p>
<select name="sensor">
<option value="DHT11">DHT11</option>
<option value="LM75A">LM75A</option>
<option value="HTU21D">HTU21D</option>
<option value="SHT31">SHT31</option>
<option value="BME280">BME280</option>
<option value="BMP280">BMP280</option>
</select>
</p>
<input type=submit value=on target=tif>
</form>
</html>
ソースコード
cppには何も書いていません。
# include <inifile.h>
# ifndef HTMLANDINIFILE_H
# define HTMLANDINIFILE_H
class WebServerToolHtmlClass {
// 空白文字の判定(タブ・スペース・改行)
bool charSpace( char chData ) { return ((chData == ' ' || chData == 0x9 || chData == 0xd || chData == 0xa) ? true : false); }
// '>' と 空白文字の判定
bool charDataTerminate( char chData ){ return ((charSpace(chData)==true || chData=='>')?true:false); }
File fp;
char *writeBuffer;
int writePos;
char readCharSkip( ){ char ch = fp.read(); return ch; }
char readChar( ){ char ch = writeBuffer[writePos] = readCharSkip(); writePos++; return ch; }
String upperCaseChar( char *str ){ String s = str; s.toUpperCase(); return s; }
//== タグを見つけて、区切り文字列を返す ========
String OLDTAG, TAG;
char readTAG() {
char chData[15], POS = 0; TAG = "";
while ( fp.available() ) {
char ch = chData[POS] = readChar();
if ( charDataTerminate(ch) ){ chData[POS] = 0x00; TAG = upperCaseChar(chData); return ch; } // タグが読めた
POS++;
}
return -1;
}
//== 設定内容の読込 (設定の右辺)=============
String detailData;
char readDetailData() {
char chData[48], POS = 0; detailData = "";
while ( fp.available() ) {
char ch = chData[POS] = readChar();
if ( charDataTerminate(ch) ){ chData[POS] = 0x00; detailData = upperCaseChar(chData);
// Serial.println( detailData );
return ch;
} // データが読めた
POS++;
}
return -1;
}
//==設定内容の読込 (設定の右辺 バッファへは移さない
char replaceDetailData( char *data ) {
int oldWritePos = writePos;
for( int POS=0 ; data[POS]!=0 ; POS++ ){ writeBuffer[ writePos ] = data[POS]; writePos++; } // データをバッファに書き出す
while ( fp.available() ) {
char ch = readCharSkip();
if ( charDataTerminate(ch) ){ // データが読めた
writeBuffer[ writePos++ ] = ch;
// writeBuffer[ writePos ] = 0; Serial.print( "[rep]=" ); Serial.println( &writeBuffer[oldWritePos] );
return ch;
}
}
return -1;
}
//==
String TYPE, NAME, VALUE, lineType, FORMNAME, OLDNAME;
//============================================
char readDetailTitle() {
char chData[48], POS = 0;
while ( fp.available() ) {
char ch = readChar();
if ( charSpace(ch) ) continue; // 読み飛ばし
if ( ch == '>' ) return ch; // 検索中に終端
chData[ POS++ ] = ch;
while ( fp.available() ) {
ch = readChar();
if ( ch == '=' ) { // タイトルが読めた
chData[ POS ] = 0x00;
String titleData = upperCaseChar( chData );
// Serial.print( "LINE:" ); Serial.print( titleData );
if( titleData=="TYPE" ){ ch = readDetailData(); TYPE = detailData.substring( 1, detailData.length()-1 ); return ch; }
if( titleData=="NAME" ){ ch = readDetailData(); NAME = detailData.substring( 1, detailData.length()-1 ); return ch; }
if( titleData=="VALUE" ){
if ( TYPE != "TEXT" && TYPE != "PASSWORD" && TYPE != "RANGE" ){
// Serial.print( "[noquate]" ); Serial.print( TYPE );
ch = readDetailData(); VALUE = detailData.substring( 1, detailData.length()-1 ); return ch; }
String tempString = "\"";
tempString += ini.get( (char*)iniHeader, (char*)NAME.c_str(), "" );
tempString += "\"";
if( tempString=="\"\"" ) ch = readDetailData(); else ch = replaceDetailData( (char*)tempString.c_str() );
return ch; }
ch = readDetailData(); return ch;
}
if( charSpace(ch) ){
chData[ POS ] = 0x00;
String titleData = upperCaseChar( chData );
// Serial.print( "SINGLE" );
// Serial.println( titleData );
if( titleData=="FORM" ) lineType = "FORM";
if( titleData=="/FORM" ) FORMNAME = ""; return ch;
}
if ( charDataTerminate( ch )==true ){ return ch; } // タイトルが読めた / 読込中に終端
chData[ POS++ ] = ch;
}
}
return -1;
}
public:
WebServerToolHtmlClass(){ writeBuffer=NULL; }
~WebServerToolHtmlClass(){ release(); }
void release(){ if( writeBuffer!=NULL ) free( writeBuffer ); writeBuffer=NULL; }
char *buffer(){ return writeBuffer; }
//============================================
char *readHtmlFile( const char *htmlFileName ) {
if( writeBuffer!=NULL ) release();
fp = SPIFFS.open( htmlFileName, "r" );
int filesize = fp.size();
writeBuffer = (char*)malloc( filesize+1000 );
writePos = 0;
FORMNAME = "";
// Serial.print( "filesize:" ); Serial.println( filesize );
while ( fp.available() ) {
if ( readChar() != '<' ) continue; // 先頭文字を探す
char ch = readTAG( ); // タグを見つけて、区切り文字列を返す
if( ch==-1 || ch=='>' ){
continue;
}else{
TYPE = ""; NAME = ""; VALUE = "";
for( ; ; ) if( !charSpace(ch=readDetailTitle()) ) break; // データを解釈する
if( ch=='>' ){
// Serial.print( "LINE NAME:" );
// Serial.print( NAME );
// Serial.print( " VALUE:" );
// Serial.println( VALUE );
if( TYPE=="RADIO" ){
String tempString = ini.get( (char*)iniHeader, (char*)NAME.c_str(), "" );
tempString.toUpperCase();
// Serial.print( " STRING:" );
// Serial.println( tempString );
if( VALUE == tempString ){
// Serial.print( "[+checked]" );
writeBuffer[ writePos-1 ] = ' ';
strcpy( &writeBuffer[ writePos ], "checked>" );
writePos += 8;
}
}
// Serial.print(TAG);
if( TAG!="OPTION" ){
OLDTAG=TAG; OLDNAME=NAME;
// Serial.println("");
}else{
// Serial.print(OLDTAG);
// Serial.print(OLDNAME);
if( OLDTAG=="SELECT" ){
String tempString = ini.get( (char*)iniHeader, (char*)OLDNAME.c_str(), "" );
tempString.toUpperCase();
// Serial.print(":");
// Serial.print(VALUE);
// Serial.print(tempString);
if( VALUE == tempString ){
writeBuffer[ writePos-1 ] = ' ';
strcpy( &writeBuffer[ writePos ], "selected>" );
writePos += 9;
}
}
Serial.println("");
}
}
}
}
// Serial.println( "[EOF]" );
writeBuffer[ writePos++ ] = 0;
fp.close();
return writeBuffer;
}
//============================================
};
WebServerToolHtmlClass WebServerToolHtml;
# endif