Yahoo! RSSニュース 電光掲示板 のhttps ( SSL )化対策 ( ESP8266 SSD1306 編)

記事公開日:2017年4月5日
最終修正日:2017年4月24日

スポンサーリンク

EasyWebSocket ライブラリを Beta ver 1.51 にアップデートしました。
スケッチも改良しました。
それによって、スクロール速度が上がりました。
以下の記事も修正しました。
(2017/4/11時点)

こんばんは。

私が過去にアップした Yahoo! Japan RSS ニュース 電光掲示板工作で、ディスプレイにニュースが突然表示されなくなってしまいました。
ESPr Developer ( ESP8266, ESP-WROOM-02 )で作ったものです。
読者の方からお知らせいただきました。
たいへん感謝いたします。
ありがとうございました。
m(_ _)m

Yahoo! Japan サイトの以下の公式記事でもお知らせがありました。

Yahoo!ニュース AOSSL対応によるURL変更のお知らせ

2017/4/5時点では、ニュース関係は https ( SSL ) 化していましたが、天気予報はまだ http でした。

世の中のセキュリティー向上意識が高まっている中で、Webページの SSL 化は仕方ないですね。
私のこのブログを随分前に SSL 化しましたが、その時は大変だったなぁ・・・。

IoT 分野でも、セキュリティー上の問題点が沢山上がっているので、電子工作分野でもその流れに乗らなくてはならないですね。

ただ、SSL は通信上のデータを暗号化するので、それを復号するために多量の文字列を扱います。
Arduino core for ESP8266 ライブラリにも https 用ライブラリがあるのですが、やはり多量のSRAM を消費してしまいます。

私の電光掲示板工作でも、多量の文字列とSRAMを消費しますので、ESP8266 ( ESP-WROOM-02 )では途端に Exception ( 例外 )エラーとなって、起動しなくなってしまいました。

今回は、自作ライブラリにhttps ( SSL )でGET要求する関数を追加して、I2C通信の小型OLED SSD1306 電光掲示板のスケッチを見直し、1文字出力する度に文字フォントを読み込むようにして、グローバル変数のメモリを劇的に減らしました。

ただ、その分、スクロール速度が遅くなってしまいました。
プログラムが動かないより良いので仕方ありません。
I2C通信は遅いので、高速スクロールには向いていませんね。
スクロール速度を上げたければ、SPIの SSD1306にするか、外付けSRAM を使うか、ESP32 ( ESP-WROOM-32 )に変えることをお勧めします。
(私は最近、ESP32 ( ESP-WROOM-32 )工作に専念しています。)

また、今回新たに ESP8266 のファームウェアを更新してみたのですが、なんと、使えるユーザーSRAM領域が減っていました。
これには参りました・・・。

今回の教訓は、

将来のことを見据えて、SRAMを極力節約したプログラムを作るべし!!

ということですね。
要するに、文字列や配列の宣言範囲を少なくするという事です。

それにしても、過去に終わった記事を修正するのは、とても時間と労力を取られてしまいます。
時間がいくらあっても足りません。
このブログの管理が大変です・・・
(自業自得です )

では、ESPr Developer ( ESP8266, ESP-WROOM-02 ) と I2C 小型 OLED SSD1306 を使った、Yahoo! RSS ニュース電光掲示板のhttps ( SSL )対策方法を説明します。
(8×8ドットマトリックスやSSD1351 の対策はまだできていません)

事前準備

使うデバイスは以下の2つです。

ESPr Developer ( ESP8266, ESP-WROOM-02 )
OLED I2C SSD1306 ( 2色 )

私が購入した販売店は既にありませんでした。
今、Amazonさんでは以下の販売店がありますが、ここでは購入したことが無いので信頼できるかどうかわかりません。

また、以下の記事を参照して、SPIFFS にフォント等のデータを事前にアップロードを済ませておいてください。

OLED ( 有機EL ) SSD1306 に16×16ドットのフリーの日本語漢字、東雲フォントを表示させてみました

Web News記事自動取得 OLED ( 有機EL )ミニ電光掲示板に16×16フリー日本語フォント( 東雲 ) を使う

SPIFFSファイルには以下が必要です。

spiffs_01.txt (HTMLヘッダ) 6KB
EwsHead2.txt (HTMLヘッダ) 8KB
shnm8x16r.bdf (8×16半角東雲フォント) 29KB
shnmk16.bdf (全角16×16ゴシック東雲フォント) 1,110KB
Utf8Sjis.tbl (私の自作、UTF8→Shift_JISコード変換テーブル) 236KB

EwsHead2.txt ファイルのIPアドレスはテキストエディタで随時変更しておくことを忘れないでください。
このファイルは、サンプルスケッチの data フォルダにもありますが、GitHub の以下のページにもアップしています。
これは、spiffs_01.txt をさらにバージョンアップした、HTMLヘッダファイルです。

https://github.com/mgo-tec/SDcard_sample_filses

改良した新しい EasyWebSocket ライブラリをインストール

Arduino IDE用の私の自作ライブラリ、EasyWebSocket ( SPIFFS用 )を改良しました。
バージョンは、Beta ver 1.49 です。
バージョンは Beta ver 1.51 です
(2017/4/11時点)

Arduino core for ESP8266 標準ライブラリの WiFiClientSecure.h をインクルードして、https ( SSL )で GET 要求する関数を追加しました。
その他細かいところを修正しています。

GitHub の以下のページから ZIPファイルをダウンロードしてください。

https://github.com/mgo-tec/ESP8266_SPIFFS_EasyWebSocket

※Arduino IDE にインストールする前に、必ず前にインストールした SPIFFS用EasyWebSocket ライブラリのフォルダごと削除してください。

ZIP形式ファイルのArduino IDEへのインストール方法やライブラリ削除方法は、以下の記事を参照してください。

自作ライブラリ EasyWebSocket のインストール方法

改良サンプルスケッチの入力

https ( SSL )化した Yahoo! Japan RSSニュース をGET できる、改良した以下のサンプルスケッチを入力してみて下さい。
今回のスケッチは SRAM 削減のため、文字列を1行のみとし、白黒反転ボタンは削除しました。

EasyWebSocket ライブラリを Beta ver 1.51 にアップデートしました。
スケッチも改良しました。
それによって、スクロール速度が上がりました。
(2017/4/11時点)
/* WebSocketリアルタイムコントロール 有機EL(OLED) 16x16東雲フォント電光掲示板サンプルスケッチ
 * Web記事取得、時計機能あり。 ESP-WROOM-02(ESP8266) および 有機EL SSD1306専用
 * License LGPL v2.1
 * Copyright (c) 2016 MGO-tec
 * 
 * ESP8266_SPIFFS_EasyWebSocket Beta ver 1.51 use.
 * 
 * ESP8266 core files are licensed under LGPL.
 * License reference URL --> https://opensource.org/licenses/LGPL-2.1
 * 
 * dataフォルダのEwsHead2.txtファイルをテキストエディタで開き、IPアドレスをご自分の環境に合わせて変えてください。
保存する時は必ず UTF-8 形式にすること
 */
#include <EasyWebSocket.h> //Beta ver 1.50 以上
#include <Wire.h>
#include <TimeLib.h> //timeライブラリver1.4の場合
#include <WiFiUdp.h>
#include <UTF8toSJIS.h>
#include <OLED_SSD1306.h>
#include <ShinonomeFONTread.h>

const char* ssid = "xxxx"; //ご自分のルーターのSSIDに書き換えてください
const char* password = "xxxx"; //ご自分のルーターのパスワードに書き換えてください
 
const char* UTF8SJIS_file = "/Utf8Sjis.tbl"; //UTF8 Shift_JIS 変換テーブルファイル名を記載しておく
const char* ZenkakuFontFile = "/shnmk16.bdf"; //全角フォントファイル名を定義
const char* HalfFontFile = "/shnm8x16r.bdf"; //半角フォントファイル名を定義
const char* EwsHeadFile = "/EwsHead2.txt"; //ブラウザに送信するHTMLヘッダファイルを定義
 
const uint8_t OLED_Adress = 0x3C; //OLED address 製品に記載の数値は7bitなので、8bitに変換して1bit右へずらした値(78>>3c)
 
EasyWebSocket ews;
UTF8toSJIS u8ts;
OLED_SSD1306 oled;
ShinonomeFONTread SFR;
 
uint16_t PingSendTime = 30000; //スマホへPingを30秒毎に送信
 
String ret_str="", scl_txt="";
 
uint8_t scl_cnt = 0;
 
uint8_t SnnmDotOut[16][16], SnnmDotOut2[16][16];
uint8_t SnnmDotCnv[16][16], SnnmDotCnv2[16][16];
uint8_t Next_buf[16][16], Next_buf2[16][16];
 
uint8_t font_buf[2][16];
uint8_t test_tmp_buf1[16], test_tmp_buf2[16], dummy_font_buf[16];
 
uint8_t sj_txt[550];
uint16_t sj_cnt = 0;
uint16_t sj_length;
uint32_t SclTime;
uint16_t SclSpeed = 0;
bool Scl_Stop = false;
uint8_t Direction = 0;
int16_t Angle = 0;
bool sjis_txt_in = false;
uint8_t scl_zenkaku = 1;
 
//-------NTPサーバー定義----------------
IPAddress timeServer(132, 163, 4, 101); // time-a.timefreq.bldrdoc.gov; //(129, 6, 15, 28)time.nist.gov NTP server
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
const int timeZone = 9;     // Tokyo
WiFiUDP Udp;
unsigned int localPort = 8888;  // local port to listen for UDP packets
time_t prevDisplay = 0; // when the digital clock was displayed
uint32_t LastTime = 0;
 
//-------時刻表示定義-------------------
String time_str, ymd_str, dummy_ymd_str;
uint8_t time_sj_txt[25], ymd_sj_txt[25];
uint16_t time_sj_length, ymd_sj_length;
const char* week_jp[7] = {"日","月","火","水","木","金","土"};
//-----Web取得定義-----------------------------------------------
uint8_t web_get = 1;
uint32_t Web_time = 0;
bool first_get = true;
bool get_http_req_status = false; //ブラウザからGETリクエストがあるかどうかの判定変数
 
//***********セットアップ***************************************************
void setup(){
  delay(1000);
  Serial.begin(115200);
  Serial.println();
  
  uint16_t i,j;
  Wire.begin(); // I2C initialise the connection
  Wire.setClock(400000); //クロックはMax 400kHz
 
  oled.Ini_OLED_SSD1306(OLED_Adress, 127); //contrast 0-255 default 127
  delay(300);
  //セットアップで全角を一旦表示させることが重要。半角だとなぜかSPIFFSファイル読み込みエラーになってしまうため。
  u8ts.UTF8_to_SJIS_str_cnv(UTF8SJIS_file, "WAIT・・・・", sj_txt, &sj_length);

  for(i=0; i<16; i++){
    SFR.SjisToShinonome16FontRead(ZenkakuFontFile, HalfFontFile, 0, 0, sj_txt[i], sj_txt[i+1], font_buf[0], font_buf[1]);
    oled.Dot_8X16_Rotation(90, font_buf[0], test_tmp_buf1, test_tmp_buf2);
    oled.OLED_8x16_Display_Out(OLED_Adress, 120-8*i, 2, test_tmp_buf1, test_tmp_buf2);
    i++;
    oled.Dot_8X16_Rotation(90, font_buf[1], test_tmp_buf1, test_tmp_buf2);
    oled.OLED_8x16_Display_Out(OLED_Adress, 120-8*i, 2, test_tmp_buf1, test_tmp_buf2);
  }
  for(i=0; i<16; i++) { //初期化しておく
    for(j=0; j<16; j++){
      if(i<2) font_buf[i][j] = 0;
      SnnmDotOut[i][j] = 0; SnnmDotCnv[i][j] = 0;
      SnnmDotOut[i][j] = 0;
      SnnmDotCnv[i][j] = 0;
      Next_buf[i][j] = 0;
    }
  }
   
  ews.AP_Connect(ssid, password);
 
  delay(500);
  //NTPサーバーから時刻を取得
  Udp.begin(localPort);
  setSyncProvider(getNtpTime);
  delay(1000);
   
  SclTime = millis();
  LastTime = millis();
  prevDisplay = now();
}
//**************メインループ*************************************************
void loop() {
  websocket_handshake(); //378行以下関数。SRAM節約の為
  
  uint16_t i;
  uint8_t cp;
 
  ret_str = ews.EWS_ESP8266CharReceive(PingSendTime); //ブラウザからのWebSocketデータ受信
 
  if(ret_str != "_close"){
    if(ret_str != "\0"){
      if(ret_str != "Ping"){
        if(ret_str[0] == 't' || ret_str[0] == 'T' ){
          scl_txt = ret_str.substring(ret_str.indexOf('|')+1, ret_str.length()-1);
          scl_txt += String(" ") + String("\0");
          switch(ret_str[0]){
            case 't':
              u8ts.UTF8_to_SJIS_str_cnv(UTF8SJIS_file, scl_txt, sj_txt, &sj_length);

              scl_cnt = 0; sj_cnt = 0; web_get = 0;
              sjis_txt_in = true; Scl_Stop = false;
              break;
          } 
          Serial.println();
          for(i=0; i<scl_txt.length(); i++){
            Serial.write(scl_txt[i]); //----Arduino IDE 1.8.2以上の場合
            //Serial.write(sj_txt[i]); //----Arduino IDE 1.8.1以下の場合、Windowsのシリアルモニター表示はShift_JISなので、このコメントを外す。
          }
          Serial.println();
          
        }else{
          switch(ret_str[4]){
            case 'S':
              SclSpeed = (ret_str[0]-0x30)*100 + (ret_str[1]-0x30)*10 + (ret_str[2]-0x30);
              SclSpeed = 200 - (floor(0.25 * SclSpeed) + 150);
              Scl_Stop = false;
              break;
            case '_':
              Scl_Stop = true;
              break;
            case 'N':
              web_get = 1;
              sjis_txt_in = false; first_get = true;
              break;
            case 'C':
              web_get = 2;
              sjis_txt_in = false; first_get = true;
              break;
            case 'E':
              web_get = 3;
              sjis_txt_in = false; first_get = true;
              break;
            case 'W':
              web_get = 4;
              sjis_txt_in = false; first_get = true;
              break;
          }
        }
        ret_str = "";
      }else{
        ret_str = "";
      }
    }
     
    if(sjis_txt_in == true){ //OLED電光掲示板スクロール
      if(millis() - SclTime > SclSpeed){
        if(scl_cnt == 8 || sj_cnt == 0){
          switch( scl_zenkaku ){
            case 1:
              scl_zenkaku = SFR.SjisToShinonome16FontRead(ZenkakuFontFile, HalfFontFile, 0, 0, sj_txt[sj_cnt], sj_txt[sj_cnt+1], font_buf[0], font_buf[1]);
              for(i=0; i<16; i++) dummy_font_buf[i] = font_buf[0][i];
              break;
            case 2:
              for(i=0; i<16; i++) dummy_font_buf[i] = font_buf[1][i];
              scl_zenkaku = 1;
              break;
          }
          scl_cnt = 0;
          sj_cnt++;
          if(sj_cnt >= sj_length) sj_cnt = 0;
        }
        
        if(Scl_Stop == false){
          for(i=0; i<16; i++){
            oled.Dot_8X16_Rotation(90, SnnmDotOut[i], SnnmDotCnv[0], SnnmDotCnv[1]);
            oled.OLED_8x16_Display_Out(OLED_Adress, i*8, 6, SnnmDotCnv[0], SnnmDotCnv[1]);
          }
          oled.Scroller_8x16Dot_Replace(Direction, Next_buf[0], SnnmDotOut[0], dummy_font_buf);
          for(i=0; i<15; i++) oled.Scroller_8x16Dot_Replace(Direction, Next_buf[i+1], SnnmDotOut[i+1], Next_buf[i]);
          
          scl_cnt++;   
        }
        SclTime = millis();
      }
    }
  }else if(ret_str == "_close"){
    ret_str = "";  scl_txt = "";
  }
  
  if(now() != prevDisplay){ //ここから時刻表示設定
    char month_chr[3], day_chr[3], h_chr[3], m_chr[3], s_chr[3];
    
    sprintf(h_chr, "%2d", hour());//ゼロを空白で埋める場合は%2dとすれば良い
    sprintf(m_chr, "%02d", minute());
    sprintf(s_chr, "%02d", second());
    sprintf(month_chr, "%2d", month());
    sprintf(day_chr, "%02d", day());
    
    time_str = String(h_chr) + ':' + String(m_chr) + ':' + String(s_chr);
    ymd_str = String(year()) + '/' + String(month_chr) + '/' + String(day_chr) + "(" + String(week_jp[weekday()-1]) + ")";
    
    uint8_t time_dot[8][16], ymd_dot[16][16]; 
      
    u8ts.UTF8_to_SJIS_str_cnv(UTF8SJIS_file, time_str, time_sj_txt, &time_sj_length);
    if(Direction != 0) Direction = 0;
    
    i=0;
    while(i<time_sj_length){
      cp = SFR.SjisToShinonome16FontRead(ZenkakuFontFile, HalfFontFile, 0, 0, time_sj_txt[i], time_sj_txt[i+1], time_dot[i], time_dot[i+1]);
      i = i + cp; //cpは全角ならば2, 半角ならば2を返る
    }
    
    if(dummy_ymd_str != ymd_str){
      u8ts.UTF8_to_SJIS_str_cnv(UTF8SJIS_file, ymd_str, ymd_sj_txt, &ymd_sj_length);
      if(Direction != 0) Direction = 0;
      i=0;
      while(i<ymd_sj_length){
        cp = SFR.SjisToShinonome16FontRead(ZenkakuFontFile, HalfFontFile, 0, 0, ymd_sj_txt[i], ymd_sj_txt[i+1], ymd_dot[i], ymd_dot[i+1]);
        i = i + cp; //cpは全角ならば2, 半角ならば1が返る。
      }
    }
    
    for(i=0; i<8; i++){
      oled.Dot_8X16_Rotation(90, time_dot[i], SnnmDotCnv2[0], SnnmDotCnv2[1]);
      oled.OLED_8x16_Display_Out(OLED_Adress, 88-i*8, 0, SnnmDotCnv2[0], SnnmDotCnv2[1]);
    } 
    
    if(dummy_ymd_str != ymd_str){
      for(i=0; i<16; i++){
        oled.Dot_8X16_Rotation(90, ymd_dot[i], SnnmDotCnv2[0], SnnmDotCnv2[1]);
        oled.OLED_8x16_Display_Out(OLED_Adress, 120-i*8, 2, SnnmDotCnv2[0], SnnmDotCnv2[1]);
      }
      dummy_ymd_str = ymd_str;
    }
    prevDisplay = now();
  }
 
  if(web_get == 0){
    if(millis()-LastTime >= 300000L){//5分毎にNTPサーバーからタイム取得
      setSyncProvider(getNtpTime);
      Serial.println(time_str);
      LastTime = millis();
    }
  }else{
    if(millis()-LastTime >= 240000L){ //Web記事取得時でもNTPサーバからタイムを補正しておく
      setSyncProvider(getNtpTime);
      LastTime = millis();
    }
  }

  if(web_get > 0){ //Web記事取得
    if(first_get == true || millis()-Web_time > 600000L){ //Web記事を10分毎に取得
      String news_str = "";
      char Web_h[3], Web_m[3];
      sprintf(Web_h, "%02d", hour());//ゼロを空白で埋める場合は%2dとする
      sprintf(Web_m, "%02d", minute());
      news_str = String("◆ ") + String(Web_h) + ":" + String(Web_m) + " ";

      switch(web_get){
        case 1:
          news_str += ews.EWS_https_Web_Get("news.yahoo.co.jp", "/pickup/rss.xml", '\n', "</rss>", "<title>", "</title>", "◆ ");
          break;
        case 2:
          news_str += ews.EWS_https_Web_Get("news.yahoo.co.jp", "/pickup/computer/rss.xml", '\n', "</rss>", "<title>", "</title>", "◆ ");
          break;
        case 3:
          news_str += ews.EWS_https_Web_Get("news.yahoo.co.jp", "/pickup/entertainment/rss.xml", '\n', "</rss>", "<title>", "</title>", "◆ ");
          break;
        case 4:
          news_str += ews.EWS_Web_Get("rss.weather.yahoo.co.jp", "/rss/days/4620.xml", '>', "</rss>", "【", " - ", "【");
          news_str.replace("(","(");
          news_str.replace(")",")");
          break;
      }
      Serial.print(F("\r\nWebGet="));
      news_str.replace("&amp;","&"); //XMLソースの場合、&が正しく表示されないので、全角に置き換える
      
      u8ts.UTF8_to_SJIS_str_cnv(UTF8SJIS_file, news_str, sj_txt, &sj_length);

      for(i=0; i<news_str.length(); i++){
        Serial.write(news_str[i]); //----Arduino IDE 1.8.2以上の場合
        //Serial.write(sj_txt[i]); //----Arduino IDE 1.8.1以下の場合、Windowsのシリアルモニター表示はShift_JISなので、このコメントを外す。
      }
      Serial.println();
      
      news_str ="";
      scl_cnt = 0; sj_cnt = 0;
      sjis_txt_in = true;
      
      Web_time = millis();
      first_get = false;
    }
  }
}
//*************************NTP Time**************************************
time_t getNtpTime()
{
  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  Serial.println("Transmit NTP Request");
  sendNTPpacket(timeServer);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      Serial.println("Receive NTP Response");
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
    }
  }
  Serial.println("No NTP Response :-(");
  return 0; // return 0 if unable to get the time
}
//*************************NTP Time**************************************
void sendNTPpacket(IPAddress &address)
{// send an NTP request to the time server at the given address
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;
  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:                 
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}
//************************* Websocket handshake **************************************
void websocket_handshake(){
  get_http_req_status = ews.Get_Http_Req_Status(); //ブラウザからGETリクエストがあったかどうかの判定

  if(get_http_req_status == true){
    String html_str1="", html_str2="", html_str3="", html_str4="", html_str5="", html_str6="", html_str7="";

    //※String変数一つにEWS_Canvas_Slider_T関数は2つまでしか入らない
    html_str1 = "<body style='background:#ddddff; color:#000;'>\r\n";
    html_str1 += ews.EWS_TextBox_Send("txt1", "任意テキスト送信、半角カタカナもOK!","送信");
    html_str1 += "<br><br>\r\n";
    html_str2 = "Scrolle Speed 1\r\n";
    html_str2 += ews.EWS_Canvas_Slider_T("Speed",200,40,"#777777","#77aaff");
    html_str2 += "<br><br>\r\n";
    html_str3 += ews.EWS_On_Momentary_Button("_SclStop", "Scrole Stop", 100,25,15,"#ffffff","#777777");
    html_str4 = "<br><br>\r\n";
    html_str5 = "<div style='width:330px; height:160px; padding:10px; background:#ccccff; border:#0000ff solid 1px;'>\r\n";
    html_str5 += "<span style = 'text-align:left;'>※ここボタンを押すとWebSocketは切断されます。<br>\r\n";
    html_str5 += "再操作する場合はWS-Reconnectボタンを押してください</span><br><center>\r\n";
    html_str5 += ews.EWS_On_Momentary_Button("News", "Top NEWS", 100,25,15,"#000000","#ffffff");
    html_str5 += "<span>  </span>\r\n";
    html_str5 += ews.EWS_On_Momentary_Button("Cnews", "PC NEWS", 110,25,15,"#000000","#ffffff");
    html_str5 += "<br><br>\r\n";
    html_str5 += ews.EWS_On_Momentary_Button("ENews", "芸能News", 110,25,15,"#000000","#ffffff");
    html_str5 += "<span>  </span>\r\n";
    html_str5 += ews.EWS_On_Momentary_Button("Weather", "Weather", 110,25,15,"#000000","#ffffff");
    html_str5 += "</center></div><br><br>\r\n";
    html_str6 = ews.EWS_Status_Text2("WebSocket Status","#555", 20,"#FF00FF");
    html_str6 += "<br><br>\r\n";
    html_str6 += ews.EWS_WebSocket_Reconnection_Button2("WS-Reconnect", "grey", 200, 40, "black" , 17);
    html_str6 += "<br><br>\r\n";  
    html_str6 += ews.EWS_Close_Button2("WS CLOSE", "#bbb", 150, 40, "red", 17);
    html_str6 += ews.EWS_Window_ReLoad_Button2("ReLoad", "#bbb", 150, 40, "blue", 17);
    html_str6 += "</body></html>\r\n";
    html_str7 = "";
    //WebSocket ハンドシェイク関数
    ews.EWS_HandShake_main(0, EwsHeadFile, "", "", "", IPAddress(0,0,0,0), html_str1, html_str2, html_str3, html_str4, html_str5, html_str6, html_str7);
  }
}

【解説】

●14-20行目:
古いスケッチでは、ESP8266WiFi.h や Hash.h をインクルードしていましたが、EasyWebSoketライブラリにインクルードしているので不要になりました。
ただ、Beta 1.51 の EasyWebSocket ライブラリでは、Arduino core for ESP8266 標準ライブラリの WiFiClientSecure.h をインクリードしているので、以前よりもメモリを多く消費するので注意です。

●47行目:
古いスケッチでは、フォントデータをfont_buf に一気に読み込んでいましたが、それが SRAM を消費する原因でした。
今回は、最小限の16×16ドット1文字分のバッファに減らしました。

●50行目:
ニュース1行分のShift_JISコードバッファは従来通り、一気に sj_txt に格納するので、これくらいは必要です。
天気予報が最も文字数が多いです。

●59行目:
文字を全角か半角かを判断するための変数を追加しました。

●80行目:
ブラウザからのGETリクエストがあったかどうかを判定するための変数を追加しました。
(2017/4/11)

●129行目:
ここは今までとは劇的に変えたところと言っても良いところです。
今までは、ブラウザに送信するHTML文字列をグローバル変数領域に格納していたため、SRAMを多量に消費していました。
そこで、それを378-415行のローカル関数内に格納することによって、その関数を出るとメモリを解放してくれるようにしました。
その分、ブラウザからページ読み込みがある度に、文字列を代入して送信することになるので、若干表示が遅くなります。
ただ、それほど顕著に遅くなったとは感じないので、良しとします。

●152-153行:
最新の Arduino IDE 1.8.2 では、なんと、シリアルモニターにUTF-8コード日本語漢字が表示できるようになりました
今までは、Windows のシリアルモニターは Shift_JIS だったのです。
そこで、1.8.2以上は UTF-8 で出力し、1.8.1 以下はコメントアウトを外して、 Shift_JIS コードで出力するようしてみました。

●191-221行:
文字ドットのスクロール方法を変えました。
半角ならば8ドット移動したらフォントから1文字読み込み、全角ならば16ドット移動したら1文字読み込むようにしました。
その結果、スクロール速度が遅くなり、カクカクとスクロールしてしまうのは仕方ないのですが、SRAM を劇的に節約できました。

●282-324行:
以前の記事では、Yahoo! Japan RSS ニュースは2種類、2行読み込んでいましたが、使えるSRAMが少なくなったので、1行にしました。

297行で、今回から初登場した、https で記事をGET 取得する関数です。

ews.EWS_https_Web_Get(”HOSTアドレス文字列”, ”ターゲットアドレス文字列”, ‘区切り文字’, “終端文字列”, “抽出開始文字列”, “抽出終了文字列”, “段落区切り文字”)

使い方は、http と同じです。
ただ、306行の天気予報だけはまだ http 通信なので、以前と同じ関数です。
以下の記事も合わせてご参照ください。

自作LED電光掲示板に Yahooニュースや 天気予報 を表示させ、さらに NTP 時計機能追加しました

因みに記事をGETする時間間隔があまりにも短いと、相手サーバーに迷惑がかかるので十分注意してください。

●378-415行:
先にも述べましたが、このローカル関数内で、HTML文字列を代入してブラウザに送信し、WebSocketハンドシェイクを済ませることによって、グローバル変数領域を節約することができました。
自作ライブラリ、ESP8266_SPIFFS_EasyWebSocket Beta 1.50 から、WebSocket ハンドシェイク構成を一新しました。
ブラウザからGETリクエストがあった場合のみ、文字列を読み込み、ローカル関数を抜けたらメモリを解放できるようにしました。
これで、https ( SSL )化された Yahoo! RSS ニュースを取得できるようになりました。
Beta ver 1.50 から以下の関数を追加しています。

Get_Http_Req_Status();

これはブラウザからGETリクエストがあった場合に true を返す関数です。

EWS_HandShake_main(セレクト番号, HTMLヘッダファイル名, “”, “”, “”, IPAddress(0,0,0,0), html_str1, html_str2, html_str3, html_str4, html_str5, html_str6, html_str7);

ハンドシェイク関数を分離して、ブラウザからリクエストが来た場合に html_str を読み込み、この関数でブラウザに出力します。
セレクト番号は今回の場合は 0 にしてください。
HTMLヘッダファイルは、今までの spiffs_01.txt や止めて、このファイルにしてください。
IPAddress は今回は関係ないので、全てゼロにしておきます。
こうすることによって、消費メモリを劇的に減らすことができました。
ただ、Canvas_Slider_T 関数を使うと、ローカル関数内でオーバーロードしてしまうので要注意です。

コンパイル実行する

では、コンパイル実行してください。

スマホ、Android7.0 Google Chrome ブラウザの画面はこんな感じです。

ESP8266_SSD1306_Yahoo_https_01

動画はこんな感じです。
昔のFRISKケースに入れたものです。
今のFRISKケースはもう少しサイズが大きいですね。
EasyWebSocket Beta ver 1.49 では以下の感じです。

スクロールスピードは格段に遅くなってしまいました。

EasyWebSocket Beta ver 1.50 ではこんな感じです。

いががでしょうか。
1.51 にアップデートしたら、けっこう速度が上がりました。
1.49 では、毎回文字列を読み込んでいたので遅くなっていたのです。
それを今回改善しました。
(2017/4/11時点)

ただ、1文字ずつ読み込むので、動作がスムースでなく、カクカクしているのは仕方ありません。
速くしたい場合は、SPI通信のOLED に変えたり、SRAMを外付けしたりしなければなりません。

一番良い方法は、ESP32 ( ESP-WROOM-32 )に変えることですかね。
SRAM も ESP8266 の5倍ありますしね。

いつか、ESP32 でもやってみる予定です。

以上、何か不具合等あったらコメント等をいただけると助かります。

ではまた・・・。

スポンサーリンク

広告 と mgo-tec電子工作 関連コンテンツ
Amazon.co.jp広告







投稿者:

mgo-tec

Arduino, ESP8266, ESP-WROOM-02 等を使って、主にスマホと連携した電子工作やプログラミング記事を書いてます。ライブラリも作ったりしてます。趣味、独学でやってますので、動作保証はしません。 電子回路やプログラミングの専門家ではありません。 畑違いの仕事をしてます。 でも、少しだけ電気の知識が必要な仕事なので、電気工事士や工事担任者等の資格は持ってます。

コメントを残す

メールアドレスが公開されることはありません。

*