WebRadio w/I2S -08 . 状態の保存

今回は、ラジオの状態を保持し次回電源を入れた時に同じ状態で再生する機能の追加です。

  • 状態を保存するファイル、”state.txt”を製作。
  • 状態保存用の関数、読み込み用の関数2つを製作。
  • ラジオ管理画面には状態保存用ボタン、”Save”を追加。
  • SetUp時に前回の状態を読み込み前回の状態を再現する。
  • その他:画面の背景を変更

スケッチは前回からの修正で製作しています。


#include <Arduino.h>
#include <WiFi.h>
#include "AudioFileSourceICYStream.h"
#include "AudioFileSourceBuffer.h"
#include "AudioGeneratorMP3.h"
#include "AudioGeneratorAAC.h"
#include "AudioOutputI2S.h"

#include <WebServer.h>
#include <ESPmDNS.h>
#include "SPIFFS.h"

// Enter your WiFi setup here:
const char *SSID = "XXXXXX";
const char *PASSWORD = "YYYYYY";

AudioGenerator *decoder = NULL;
AudioFileSourceICYStream *file;
AudioFileSourceBuffer *buff;
AudioOutputI2S *out;

// Controll flg
static int8_t flg[10];
#define play    0
#define volume  1
#define total   2
#define now     3

WebServer server(80);

String index_Dt =
                  "<!DOCTYPE html>\n<html>\n<head>\n"
                  "<title>ESP32 WebRadio</title>\n</head>\n"
                  "<body>\n<center>\n"
                  "<div style='width:250px; background-color:#d8a373; border-style:solid; border-radius:30px; border-color:#6b3f31;'>\n"
                  "<h2>ESP32 WebRadio</h2>\n"
                  "<form id='pull_list' method='get'>\n"
                  "<select name='5' id='pull_item' onchange='getItem()'>\n";
                  
String index_Dt1 =
                  "</select><br><br>\n"
                  "</form>\n"

                  "<form id='cmd_vol' method='get'>\n"
                  "<input type='range' min='0' max='100' step='1' name='3' onchange='showValue()' id='s_value' value='50'>\n"
                  "<span id='p_value'>50</span><br>\n"
                  "</form><br><br>\n"

                  "<form method='get'>\n"
                  "<button type='submit' name='1' id='b_play' style='background:#90ee90'>PLAY</button>\n"
                  "<button type='submit' name='2' style='background:#90ee90'>STOP</button>\n"
                  "<button type='submit' name='4' id='b_mute' style='background:#90ee90'>MUTE</button><br><br>\n"
                  "<button type='submit' name='6' style='background:#90ee90'>Entry</button>\n"
                  "<button type='submit' name='8' style='background:#90ee90'>Save</button>\n"
                  "</form><br>\n"
                  
                  "</div>\n<script>\n"
                  "function showValue() {\n"
                  "target = document.getElementById('cmd_vol');\n"
                  "target.submit();\n}\n"
                  
                  "function getItem() {\n"
                  "target = document.getElementById('pull_list');\n"
                  "target.submit();\n}\n";
                  
void setup()
{
  Serial.begin(115200);
  delay(1000);
  Serial.println("Connecting to WiFi");

  WiFi.disconnect();
  WiFi.softAPdisconnect(true);
  WiFi.mode(WIFI_STA);
  
  WiFi.begin(SSID, PASSWORD);

  // Try forever
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println("...Connecting to WiFi");
    delay(1000);
  }
  Serial.println("Connected");
  Serial.println(SSID);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  if (MDNS.begin("esp32")) {
    Serial.println("MDNS responder started");
  }
  
  server.on("/", handleRoot);
  
  server.begin();
  Serial.println("HTTP server started");

  out = new AudioOutputI2S();

  //Initialize File System
  SPIFFS.begin();
  Serial.println("File System Initialized");    //Initialize File System

  load_flg();
  out->SetGain((float)flg[volume]/100.0);
  if(flg[play]) radio_play(flg[now]);
}

void loop()
{
  if(flg[play])
  {
    if (decoder->isRunning()) {
      if (!decoder->loop()) decoder->stop();
    } 
    else {
        Serial.print("decoder done\n");
        StopPlaying();    
        delay(500);
        radio_play(flg[now]);
    }
  }

  server.handleClient();
}

void handleRoot()
{
  String cmd;
  int a,fl;

    fl=1;
    cmd=server.argName(0);
    switch(cmd.toInt())
    {
      case 1:   // Play 
                if(flg[play] == 0)
                   if(flg[total] != flg[now])
                       radio_play(flg[now]);
                break;
                
      case 2:   // Stop 
                StopPlaying();
                break;
                
      case 3:   // Volume 
                cmd=server.arg("3");
                flg[volume]=cmd.toInt();
                out->SetGain((float)flg[volume]/100.0);
                break;
                
      case 4:   // Mute
                flg[volume] *= -1;
                a=flg[volume];
                if(flg[volume] < 0) a=0;
                out->SetGain(((float)a)/100.0);
                break;
                
      case 5:   // List
                cmd = server.arg("5");
                flg[now] = cmd.toInt();
                break;

      case 6:   // Entry Sheet
                entry_sheet();
                fl=0;
                break;

      case 7:   //Edit(0) / ADD(1) / delete(2) OK
     
                cmd = server.arg("7");
                
                a=1;
                if(flg[total] == flg[now]) 
                  if(cmd.charAt(0) != '1') a=0;

                if(a) make_file(flg[now],cmd);
                break;

      case 8:   // save data
                save_flg();                
                break;
    }

  if(fl) load_index();
  else server.send(204, "text/plane",""); 
}

void load_index()
{
  int a;
  File dataFile;
  String line,line1,stbuf;
  
    //Pull Down List
    flg[total] = 0;
    a = flg[now];

    dataFile = SPIFFS.open("/title.txt", FILE_READ);
    stbuf="";
    while(dataFile.available())
     {
       line = dataFile.readStringUntil('\n');
       stbuf += "<option value='" + String(flg[total]+1) + "'";
       a -= 1; 
       if(a) stbuf += ">"; 
       else { stbuf += " selected>"; line1=line; }
        
       if(line != "<--- end --->") stbuf = stbuf + String(flg[total]+1) + ": ";
       stbuf = stbuf + line + "</option>\n";
       flg[total] += 1;
     }
    dataFile.close();
    
    stbuf = index_Dt + stbuf + index_Dt1;

    stbuf += ("document.getElementById('s_value').value='" + String(abs((int)flg[volume])) + "'\n");
    stbuf += ("document.getElementById('p_value').innerHTML='" + String(abs((int)flg[volume])) + "'\n");
 
    if(flg[play])
      stbuf += ("document.getElementById('b_play').style.backgroundColor='#ff6347'\n");
    if(flg[volume] < 0)
      stbuf += ("document.getElementById('b_mute').style.backgroundColor='#2020ff'\n");

    stbuf += "history.pushState(null,null,'/');\n</script>\n</center>\n</body>\n</html>";
   
  server.send(200, "text/html",stbuf);    
}

void radio_play(int no)
{
  File l_file;
  int a;
  String link_data;

    l_file = SPIFFS.open("/link_list.txt", FILE_READ);  
    for(a=0; a<no; a ++) link_data=l_file.readStringUntil('\n');
    l_file.close();

    file = new AudioFileSourceICYStream(link_data.substring(2).c_str());
    buff = new AudioFileSourceBuffer(file, 2048*16);
    
    if(link_data.charAt(0) == '1') decoder = (AudioGenerator*) new AudioGeneratorAAC();
    else decoder = (AudioGenerator*) new AudioGeneratorMP3();

    decoder->begin(buff, out);
    
    flg[play]=1;
}
  
void StopPlaying()
{
  if (decoder) { decoder->stop(); delete decoder; decoder = NULL; }
  if (buff) { buff->close(); delete buff; buff = NULL; }
  if (file) { file->close(); delete file; file = NULL; }
  
  flg[play] = 0; 
}

void entry_sheet()
{
  File dataFile,dataFile1;
  String line,line1,html_buf;
  int a;

    dataFile = SPIFFS.open("/entry.txt", FILE_READ);
    html_buf="";
    while(dataFile.available())
    {
      html_buf += dataFile.readStringUntil('\n');
      html_buf += "\n"; 
    }
    dataFile.close();

    dataFile = SPIFFS.open("/title.txt", FILE_READ);
    dataFile1 = SPIFFS.open("/link_list.txt", FILE_READ);
    for(a=0; a<flg[now]; a++)
    {
      line = dataFile.readStringUntil('\n');
      line1 = dataFile1.readStringUntil('\n');  
    }
    dataFile.close(); dataFile1.close();
                
    html_buf += "document.getElementById('m_title').value='" + line + "';\n"
                "document.getElementById('m_link').value='" + line1.substring(2) + "';\n"
                "var mp_acc = document.getElementsByName( 'a2' ) ;\n";

    if(line1.charAt(0) == '1') html_buf += "mp_acc[1].checked = true; \n";        
                            
    html_buf += "history.pushState(null,null,'/');\n</script>\n</body>\n</html>\n";

    server.send(200, "text/html", html_buf);
}

void make_file(int no, String line)
{
    File t,t1,l,l1;
    String d_data,l_data,s_data[3];
    int a,b;

        s_data[0]=line.charAt(0);
                
        b=2; a=2;
        while(a)
         {
           while(line.charAt(b) != ',') b ++;
           a --; b ++;
         }
        s_data[1]=line.substring(2,b-1);
        s_data[2]=line.substring(b);

        a = s_data[0].toInt();
        t = SPIFFS.open("/title.txt",FILE_READ); t1 = SPIFFS.open("/title.tmp",FILE_WRITE);
        l = SPIFFS.open("/link_list.txt",FILE_READ); l1 = SPIFFS.open("/link_list.tmp",FILE_WRITE);
        while(t.available())
        {
          d_data = t.readStringUntil('\n'); l_data = l.readStringUntil('\n');
          no --;
          switch(a)
          {
            case 0: //Edit
                    if(no == 0)
                    { 
                      t1.print(s_data[2] + "\n"); 
                      l1.print(s_data[1] + "\n"); 
                    }
                    else 
                    { 
                      t1.print(d_data + "\n"); 
                      l1.print(l_data + "\n"); 
                    }
                    break;

            case 1: // Add
                    if(no == 0) 
                    { 
                      t1.print(s_data[2] + "\n"); 
                      l1.print(s_data[1] + "\n"); 
                    }
                    t1.print(d_data+"\n"); l1.print(l_data + "\n");
                    break;

            case 2: // Delete
                    if(no != 0) 
                    { 
                      t1.print(d_data + "\n"); 
                      l1.print(l_data + "\n"); 
                    }
                    break;
          }
        }
        t.close(); t1.close(); l.close(); l1.close();

        SPIFFS.remove("/title.txt");
        SPIFFS.remove("/link_list.txt");
        SPIFFS.rename("/title.tmp","/title.txt");
        SPIFFS.rename("/link_list.tmp","/link_list.txt");

        if(s_data[0] == "1") flg[total] ++; 
        if(s_data[0] == "2") flg[total] --; 
       
}

void save_flg()
{
  int a;
  File dataFile;
    
    dataFile = SPIFFS.open("/state.txt", FILE_WRITE);
    for(a=0; a<4; a ++) 
    {
      dataFile.print(flg[a]);
      dataFile.print("\n");
    }
    dataFile.close();
}

void load_flg()
{
  int a;
  String line;
  File dataFile;
    
    dataFile = SPIFFS.open("/state.txt", FILE_READ);
    for(a=0; a<4; a++)
    {
      line = dataFile.readStringUntil('\n');
      flg[a] = line.toInt();
    }
    dataFile.close();
}
  • 35行:バックグランドの色を指定。
  • 54行:この部分で、”Save”ボタンの追加。
  • 103行:load_flg();
    • 状態読み込み関数。
    • 前の状態をファイル、”state.txt”から読み込み、状態パラメータにセットする。
  • 104行:音量設定
  • 105行:前回再生中ならその局を再生
  • 363から375行: 状態保存関数、”save_flg()”の本体
  • 377から390行: 状態読み込み関数、”load_flg()”の本体

今回追加された、”state.txt”ですが、内容は以下の様になっています。


0
35
5
1

現在ラジオ管理に、Play、Volume,Total,Nowの4つのパラメータを使用しています。それが上から順にセーブされています。前回使用した、”entry.txt”,”title.txt”,”link_list.txt”の3つのファイルとこの、”state.txt”を、”data”フォルダーに保存して下さい。

コンパイル。データアップロード後、実行して下さい。”Save”ボタンが追加された管理画面が出ます。

この様に背景色と枠を追加して見ました。

実際の使い方ですが、例えば、

  • ある局を再生中に、”Save”ボタンを押します。
  • そのままESP32の電源を切る。
  • EPS32の電源を入れると、前回再生していた局と音量を再現して再生

今回で終了です。今回のスケッチをここに置きます。ー>スケッチ