大き目ドットの有機EL, WS0010 で Yahoo ニュース リアルタイム 電光掲示板を作ってみた

ESP8266 ( ESP-WROOM-02 )
SPIFFS用 EasyWebSocket ライブラリを更新し、Yahoo ニュース記事を取得した後も Websocket通信が継続するように修正しました。
beta ver 1.52.0 になっています。
https://github.com/mgo-tec/ESP8266_SPIFFS_EasyWebSocket
(2018/04/29)
Yahoo!ニュース RSS サイトが https ( SSL )化されて、しばらく経ちました。
この記事のコメント欄でYahoo ニュースが表示されないなどの不具合があり、再度検証して、ソースコードを修正しました。
また、ShinonomeFNTreadライブラリと、Utf8sjisライブラリもバージョンアップしました。
(2017/12/18時点)

※ ESP-WROOM-02 の Flashメモリサイズが 4MB のはずが、実は 2MB だったという情報がありました。
以下のページを参照して、Flashメモリサイズを確認しておくことを強くお勧めします。

ESP-WROOM-02 ( ESP8266 ) チップ・メモリ・MACアドレス情報確認方法
Flashメモリサイズが 2MB の場合はここで掲載しているプログラムは動作しませんので、4MBの ESP-WROOM-02 を購入してください。
(2017/10/2)

こんばんは。

前回の記事に引き続き、今回は Yahoo! RSS のニューストピックス電光掲示板を作ってみました。
大き目ドットのキャラクタ&グラフィック有機EL WS0010 に表示させていて、ESPr Developer ( ESP-WROOM-02, ESP8266 ) とGPIO エキスパンダ MCP23S08 を使用しています。

以下の記事

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

でも同じようなことをやりましたが、今回は何といっても文字が大きいというところがミソです。16×16ドットの日本語漢字が高速スクロールできるというところが違います。

また、こちらの記事

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

では、文字は大きくて高速スクロールしますが、8×8ドットなので、複雑な漢字は読み取りにくいものでした。

ということで、今回でこの Yahoo! RSS ニュース 電光掲示板は私にとってほぼ理想的なものとなりました。
ケースを加工すれば、デスクトップにどこでも設置できるWEB連携 電光掲示板 として、とてもイイ具合ではないでしょうか。

ということで、まずは以下の動画をご覧ください。

いかがでしょうか。
NTP時刻自動補正、時計表示もあります。
ちなみに、この動画ではデジカメのフレームレートが合わなくて、スクロールが多少カクカクしているところがありますが、実際はもっとスムースにスクロールしています。
Yahoo RSS ニュース電光掲示板として、手作りでここまでできれば十分でしょう。

比較のために、過去に作った有機EL ( OLED )のWEB連動電光掲示板を集めた動画はこんな感じになります。

やっぱり、一人で見る分には小さい文字でも良いですけど、他人にメッセージを伝えるには大きい文字でないとダメですね。
比較するとストロベリーリナックスさんのグラフィック有機EL は格段に文字が大きいことが分かると思います。

ちなみに、RSSニュースはもっと沢山のバリエーションがあります。
スポーツ報知や日経、ITmediaなど・・・、
パソコンで見る場合には以下のリンクを見てみてください。

Yahoo! ニュース RSS

ただ、残念なのが、このESP-WROOM-02 ( ESP8266 ) のSRAM メモリでは足りなくて、トピックス以外のニュースは見ることが出来ません
文字列の処理にメモリを食い過ぎてます。
これはいつか改善したいと思いますが、ここのところ忙しくてあまり詰めていません。
良い方法があったら教えていただけると幸いです。

ESP-WROOM-02 ( ESP8266 ) というものは、SRAMが膨大にあるかと思いきや、無作為に使ってしまうと意外と少ない容量です。
今回の場合、半角で1024文字を超えると例外エラーとなったり、文字列を受信できなかったりと、いろいろ悩みました。
スポーツ報知などの記事を取得すると、文字列が1500を超えて、電光掲示板に表示すらできませんでした。

メモリの節約をして、SPIFFSにWebSocketページを全て入れてしまうという手もあったのですが、使い勝手の点から今回は見送りました。
皆さんも試していただければ、もしかしたらスポーツ報知の記事も取得できるかもしれません。

では、前置きが長くなりましたが、解説していこうと思います。

スポンサーリンク

1.使うもの

前回の記事と同様ですが、はじめて見る方のためにザッと紹介しておきます。

8ビット SPI I/Oエキスパンダ MCP23S08-E/P

秋月電子通商さんで販売。
Microchip製です。
これは5V駆動ですのでご注意ください
SPI通信の最大速度は10MHz です。
ESPr Developer ( ESP-WROOM-02, ESP8266 )ではGPIOピンが少ないので、これを使って増設します。
これで8bitモードパラレルのディスプレイが制御できます。

グラフィック有機ELモジュール100x16

ストロベリーリナックス ( Strawberry Linux )さんで販売しています。
コントローラーは WS0010 を使ってます。
キャラクタモードとグラフィックモードを切り替えできます。

ESPr Developer ( ESP-WROOM-02 開発ボード )
スイッチサイエンス製
Amazon.co.jp

ESP-WROOM-02開発ボード
スイッチサイエンス(Switch Science)

ESPr Developer(ピンソケット実装済)
スイッチサイエンス(Switch Science)

これについては何度も当ブログで紹介しておりますが、日本の電波法をクリアした技適認証済み Wi-Fi モジュールです。ESP-WROOM-02 が安定して動作して、とても使いやすいです。
Arduino IDE で開発ができて、とてもお勧めです。
これの使い方については以下のページを参照してください。
https://www.mgo-tec.com/blog-entry-ss-wroom-howto01.html

0.1uF セラミックコンデンサー
I/Oエクスパンダの MCP23S08 チップの電源ノイズ対策のパスコンです。
積層セラミックで良いです。

サンハヤト製ニューブレッドボード 【SAD-101】
このブレッドボードがお勧めです。

サンハヤト SAD-101 ニューブレッドボード
サンハヤト
¥529(2024/03/28 14:27時点)

その他、ジャンパーワイヤー、パソコン、USBケーブル等

2.接続、Arduino IDE 設定、SPIFFS設定、ライブラリインストール等

前回の記事 1~5 までの設定をを予め済ませておいてください。
SPIFFSアップロードのところでは、spiffs_01.txt のIPアドレスをご自分のルーターで割り当てたESPr Developer のローカルIPアドレスに書き換えることを忘れないでください

その他、今回はTimeライブラリを使用します。
時計を表示するために必要なのです。
Timeライブラリのインストール方法は以下の記事を参照してください。

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

その他、以下のライブラリは少々変更してバージョンアップしました。

●ShinonomeFONTread ライブラリ

Beta ver 1.33 → Beta ver 1.40
(2017/12/18更新)

●UTF8 to Shift_JIS ライブラリ

Beta ver 1.41 → Beta ver 1.50
(2017/12/18更新)

●EasyWebSocket(SPIFFS) ライブラリ

SPIFFS用 EasyWebSocket ライブラリを更新し、Yahoo ニュース記事を取得した後も Websocket通信が継続するように修正しました。
beta ver 1.52.0 になっています。
https://github.com/mgo-tec/ESP8266_SPIFFS_EasyWebSocket
(2018/04/29)

ライブラリをバージョンアップしてインストールする場合は、必ず古いライブラリのフォルダごと削除してから再インストールすることを忘れないでください

3.スケッチの入力

今回は、WS0010 や MCP23S08 をライブラリ化していないので、かなり長いソースコードになります。

以下のコードをArduino IDE に入力してください。

Yahoo Japan RSSサイトの SSL化に伴い、プログラムとライブラリを修正しました。
ShinonomeFNTread beta 1.40以上と Utf8SJIS beta 1.50以上を使用してください。
(2017/12/18)

【ソースコード】 (※無保証 ※PCの場合、ダブルクリックすればコード全体を選択できます)

/* 
 * ESPr Developer or ESP-WROOM-02 or ESP8266
 * GPIO Expander = MCP23S08 ( Microchip )
 * OLED = WS0010 ( Strawberry Linux )
 * The MIT License (MIT)
 * Copyright (c) 2016 mgo-tec 
 * License reference URL --> https://opensource.org/licenses/mit-license.php
 */

#include <SPI.h>
#include <ShinonomeFONTread.h> // beta ver1.40
#include <UTF8toSJIS.h> // beta ver1.50
#include <EasyWebSocket.h> //EasyWebSocket_SPIFFS beta ver1.52.0
#include <Hash.h>
#include <TimeLib.h> //timeライブラリver1.4の場合
#include <WiFiUdp.h>

//ESP8266 GPIO Register Direct Access 設定
#define PIN_OUT_SET *(volatile uint32_t *)0x60000304 //※PIN_OUTだけの場合は他のピンまで影響を与えるが、PIN_OUT_SETはターゲットピンのみアサインできる
#define PIN_ENABLE_SET *(volatile uint32_t *)0x60000310 //※PIN_ENABLEだけの場合は他のピンまで影響を与えるが、PIN_ENABLE_SETはターゲットピンのみアサインできる
#define PIN(a)  *(volatile uint32_t *)(0x60000328 + (a)*4) //#define設定で引数を使う方法

const char* ssid = "xxxx"; //ご自分のルーターのSSIDに書き換えてください。
const char* password = "xxxx"; //ご自分のルーターのパスワードに書き換えてください。

//GPIOエクスパンダ MCP23S08 のSPIインターフェースピン設定
const uint8_t sclk = 14;
const uint8_t mosi =13; //Master Output Slave Input ESP8266=Master,MCP23S08=slave 
const uint8_t MCP_CS = 0;
const uint8_t MCP_RST_pin =  16;
//OLED ピン設定 (8bitモード用)
const uint8_t OLED_RS_pin = 2;
const uint8_t OLED_RW_pin =  5;
const uint8_t OLED_E_pin = 4;

const char* UTF8SJIS_file = "/Utf8Sjis.tbl"; //UTF8 Shift_JIS 変換テーブルファイル名を記載しておく
const char* ZenkakuFontFile = "/shnmk16.bdf"; //全角フォントファイル名を定義
const char* HalfFontFile = "/shnm8x16r.bdf"; //半角フォントファイル名を定義

UTF8toSJIS u8ts;
ShinonomeFONTread SFR;
EasyWebSocket ews;

File __UtoS; //Utf8SJIS beta ver 1.50 use.

enum { MaxTxt = 800 , DispChar = 12}; //MaxTxt = スクロールする文字列の最大数
                                      //DispChar = ディスプレイに表示できる半角文字の数
uint8_t font_buf[16][16];
uint8_t SnnmDotOut[DispChar][16];
uint8_t Next_buf[DispChar][16];
uint8_t dummy_font_buf[16];
String html_str1 = "", html_str2 = "", html_str3 = "", html_str4 = "", html_str5 = "", html_str6 = "", html_str7 = "";

int PingSendTime = 30000;

//-------NTPサーバー定義-----------------------------
IPAddress timeServer(52, 168, 138, 145); // time.windows.com
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 LastNTP_Get = 0;
//-----時計表示引数定義------------------------------ 
boolean clock_Disp_Set = false, clock_Disp_OUT = false;
uint8_t clock_Select = 0;
uint32_t sec_colon_time = 0;
//-----Yahoo記事取得引数定義-------------------------
uint32_t Web_time = 0;
boolean Web_first_get = true, Text_Box_On = false;
uint8_t Yahoo_get = 1;
uint8_t sj_txt[MaxTxt];
uint16_t sj_cnt = 0;
uint16_t sj_length;
uint32_t SCLtime;
uint16_t Scrolle_speed = 8;
uint8_t scl_cnt = 0;
boolean fnt_read_ok = true;
uint8_t Zen_or_Han_cnt = 0;
uint8_t Zen_or_Han = 0;
uint8_t bufff[2][16] = {0};

//***************セットアップ**********************************************
void setup() {
  char c1[64] = "----- W a i t -----."; //1列最大64文字格納。そのうち20文字表示
  char c2[17] = "Connecting Wi-Fi"; //1列最大64文字格納。そのうち20文字表示
  int i, j;
  Serial.begin(115200);
  Serial.println();
  delay(10);
  //ESP8266 GPIO Register Direct Access 設定。ターゲットピンのみアサイン。
  PIN_OUT_SET = (1<<OLED_RW_pin | 1<<OLED_E_pin | 1<<OLED_RS_pin | 1<<MCP_CS);
  PIN_ENABLE_SET = (1<<OLED_RW_pin | 1<<OLED_E_pin | 1<<OLED_RS_pin | 1<<MCP_CS);
  PIN(MCP_CS) = 0; //HIGH
  PIN(OLED_E_pin) = 1; //LOW
  pinMode(MCP_RST_pin, OUTPUT);
  digitalWrite(MCP_RST_pin, HIGH);

  MCP23S08_Ini(); //GPIOエキスパンダ MCP23S08初期化
  delay(1000);
  OLED_Character_Ini(); //OLEDキャラクタモード初期化
  for(i=0; i<64; i++){ //1列最大64文字格納。そのうち20文字表示
    OLED_DataWrite(c1[i]);
  }
  for(i=0; i<16; i++){ //1列最大64文字格納。そのうち20文字表示
    OLED_DataWrite(c2[i]);
  }

  html_str1 += "<body style='background:#000; color:#fff;'>\r\n";
  html_str1 += "<font size=3>\r\n";
  html_str1 += "ESP-WROOM-02(ESP8266)\r\n";
  html_str1 += "<br>\r\n";
  html_str1 += "EasyWebSocket Beta1.45 Sample\r\n";
  html_str1 += "</font><br><br>\r\n";
  html_str1 += ews.EWS_TextBox_Send("txt1", "Hello Easy WebSocket Beta1.3","送信");
  html_str2 += "<br>Scrolle Speed\r\n";
  html_str2 += ews.EWS_Canvas_Slider_T("SPEED",200,40,"#777777","#0000ff");
  html_str2 += "<br><br><br>\r\n";
  html_str3 += ews.EWS_On_Momentary_Button("Clock", "時計(秒表示)", 100,25,15,"#ffffff","#00aa00");
  html_str3 += "  \r\n";
  html_str3 += ews.EWS_On_Momentary_Button("clock", "時計(月日表示)", 120,25,15,"#ffffff","#00aa00");
  html_str3 += "<br><br>\r\n";
  html_str4 += "<fieldset style='border-style:solid; border-color:gray'>\r\n";
  html_str4 += "<legend style='font-style: italic; color:grey;'>Yahoo! News Topics</legend>\r\n";
  html_str4 += ews.EWS_On_Momentary_Button("1Yahoo", "Yahoo!ニュースTOP", 200,30,15,"white","#ff7766");
  html_str4 += "<br><br>\r\n";
  html_str4 += ews.EWS_On_Momentary_Button("2Yahoo", "Yahoo!エンタメ", 200,30,15,"white","#ff7766");
  html_str4 += "<br><br>\r\n";
  html_str4 += ews.EWS_On_Momentary_Button("3Yahoo", "Yahoo!スポーツ", 200,30,15,"white","#ff7766");
  html_str4 += "<br><br>\r\n";
  html_str4 += ews.EWS_On_Momentary_Button("4Yahoo", "Yahoo!天気予報(東京)", 200,30,15,"white","#ff7766");
  html_str4 += "</fieldset>\r\n";
  html_str4 += "<br>\r\n";
  html_str5 += ews.EWS_Status_Text2("WebSocket Status","#555", 20,"#FF00FF");
  html_str5 += "<br>\r\n";
  html_str7 += ews.EWS_WebSocket_Reconnection_Button2("WS-Reconnect", "grey", 200, 40, "black" , 17);
  html_str7 += "<br><br>\r\n";  
  html_str7 += ews.EWS_Close_Button2("WS CLOSE", "#ccc", 150, 40, "red", 17);
  html_str7 += ews.EWS_Window_ReLoad_Button2("ReLoad", "#ccc", 150, 40, "blue", 17);
  html_str7 += "</body></html>\r\n";

  for(i=0; i<16; i++) { //初期化しておく
    for(j=0; j<16; j++){
      font_buf[i][j] = 0; SnnmDotOut[i][j] = 0; Next_buf[i][j] = 0;
    }
  }

  ews.AP_Connect(ssid, password);
  delay(1000);

  //NTPサーバーから時刻を取得
  Udp.begin(localPort);
  setSyncProvider(getNtpTime);
  delay(1000);
  OLED_Graphic_Ini(); //OLED WS0010 初期化

  SFR.SPIFFS_Shinonome_Init3F(UTF8SJIS_file, HalfFontFile, ZenkakuFontFile);

  SCLtime = millis();
  prevDisplay = now();
  LastNTP_Get = millis();
}
//***************メインループ*************************
void loop() {
  ews.EWS_HandShake(html_str1, html_str2, html_str3, html_str4, html_str5, html_str6, html_str7);

  int i,j;
  String ret_str = "";

  if(ret_str != "_close"){
    ret_str = ews.EWS_ESP8266CharReceive(PingSendTime);
    if(ret_str != "\0"){
      if(ret_str != "Ping"){
        if(ret_str[0] != 't'){
          int ws_data = (ret_str[0]-0x30)*100 + (ret_str[1]-0x30)*10 + (ret_str[2]-0x30);
          switch(ret_str[4]){
            case 'S':
              Scrolle_speed = floor((200-ws_data)/(200/40)); //スマホスライダー値(0-200)で、値を(40-0)に変更したい場合
              Serial.print("Scrolle_speed = "); Serial.println(Scrolle_speed);
              break;
            case 'C':
              clock_Disp_Set = true; Text_Box_On = false;
              clock_Select = 0;
              break;
            case 'c':
              clock_Disp_Set = true; Text_Box_On = false;
              clock_Select = 1;
              sec_colon_time = millis();
              break;
            case '1':
              Yahoo_get = 1;
              Web_first_get = true; clock_Disp_Set = false; Text_Box_On = false;
              break;
            case '2':
              Yahoo_get = 2;
              Web_first_get = true; clock_Disp_Set = false; Text_Box_On = false;
              break;
            case '3':
              Yahoo_get = 3;
              Web_first_get = true; clock_Disp_Set = false; Text_Box_On = false;
              break;
            case '4':
              Yahoo_get = 4;
              Web_first_get = true; clock_Disp_Set = false; Text_Box_On = false;
              break;
          }
          Serial.println(ret_str);
        }else if(ret_str[0] == 't'){
          String txt;
          txt = ret_str.substring(ret_str.indexOf('|')+1, ret_str.length()-1);
          sj_cnt = 0;
          int t_len = txt.length();
          if(t_len < 20){
            for(i=0; i<(20-t_len); i++){
              txt += ' ';
            }
          }
          txt = "  " + txt;
          u8ts.UTF8_to_SJIS_str_cnv(txt, sj_txt, &sj_length);
          Serial.print ("txt = "); Serial.println(txt);

          for(i=0; i<16; i++) dummy_font_buf[i] = font_buf[0][i];
          Text_Box_On = true; clock_Disp_Set = false;
        }
      }
    }
  }else if(ret_str == "_close"){
    ret_str = "";
  }

  if((clock_Disp_Set == false) && (millis()-SCLtime > Scrolle_speed)){ //文字スクロール
    Scroller_8x16x12_Dot_Replace(DispChar, Next_buf, SnnmDotOut, dummy_font_buf, font_buf, sj_length, &scl_cnt, &sj_cnt);
    OLED_8x16x12_Font_DisplayOut(DispChar, SnnmDotOut);
    SCLtime = millis();
  }

  if(clock_Disp_Set == true){ //時計表示
    Clock_Display(clock_Select);
  }

  if(millis()-LastNTP_Get > 3600000UL){ //1時間ごとに時刻補正
    setSyncProvider(getNtpTime);
    LastNTP_Get = millis();
    Serial.println("---------------NTP time acquisition completed");
  }

  if(Text_Box_On == false && clock_Disp_Set == false){
    if(Web_first_get == true || millis()-Web_time > 600000UL){ //Web記事を10分毎に取得
      String news_str;
      String news1_1_target_ip;

      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(Yahoo_get){
        case 1:          
          news1_1_target_ip = "/rss/topics/top-picks.xml"; // Yahoo!ニューストピックストップ
          news_str += ews.EWS_https_Web_Get("news.yahoo.co.jp", news1_1_target_ip, '\n', "</rss>", "<title>", "</title>", "◆ ");
          break;
        case 2:
          news1_1_target_ip = "/rss/topics/entertainment.xml"; // Yahoo!エンタメ
          news_str += ews.EWS_https_Web_Get("news.yahoo.co.jp", news1_1_target_ip, '\n', "</rss>", "<title>", "</title>", "◆ ");
          break;
        case 3:
          news1_1_target_ip = "/rss/topics/sports.xml"; // Yahoo!スポーツ
          news_str += ews.EWS_https_Web_Get("news.yahoo.co.jp", news1_1_target_ip, '\n', "</rss>", "<title>", "</title>", "◆ ");
          break;
        case 4:
          news1_1_target_ip = "/rss/days/4410.xml"; // Yahoo!天気予報(東京)
          news_str += "東京の天気◆";
          news_str += ews.EWS_https_Web_Get("rss-weather.yahoo.co.jp", news1_1_target_ip, '>', "</rss>", "【", "Yahoo!", "【");
          news_str.replace(" 東京(東京) ","");
          break;
      }

      Serial.print("\r\nWebGet str = ");
      news_str.replace("&amp;","&"); //XMLソースの場合、&が正しく表示されないので、全角に置き換える
      u8ts.UTF8_to_SJIS_str_cnv(news_str, sj_txt, &sj_length);

      for(i=0; i<16; i++) dummy_font_buf[i] = font_buf[0][i]; //1文字目を予め入力しておく
      Serial.print(news_str);
      Serial.println(); Serial.print("sj_length="); Serial.println(sj_length);
      news_str ="";
      scl_cnt = 0; sj_cnt = 0;
      Web_first_get = false;
      Web_time = millis();
    }
  }
}
//*********GPIOエキスパンダMCP23S08初期化関数********************
void MCP23S08_Ini(){ 
  SPI.begin();
  SPI.setFrequency(10000000); //MCP23S08 Max 10MHz
  SPI.setDataMode(SPI_MODE0);

  digitalWrite(MCP_RST_pin, HIGH);
  delay(10);
  digitalWrite(MCP_RST_pin, LOW);
  delay(100);
  digitalWrite(MCP_RST_pin, HIGH);
  delay(50);

  PIN(MCP_CS) = 1; //LOW
    delay(1);
    SPI.write(B01000000);//デバイスオペコードB01000000 & チップaddress 000
    SPI.write(0x06);//MCP設定レジスタIOCON 
    SPI.write(B00100000);//シーケンシャル動作禁止、SDAスルーレート許可、ハードウェアアドレスピン禁止、INT出力LOW、アクティブドライブ
    delay(1);
  PIN(MCP_CS) = 0; //HIGH

  PIN(MCP_CS) = 1; //LOW
    delay(1);
    SPI.write(B01000000);//デバイスオペコードB01000000 & チップaddress 000
    SPI.write(0x00);// I/O方向レジスタ(IODIR)設定
    SPI.write(B00000000);//8pin ALL OUTPUT
    delay(1);
  PIN(MCP_CS) = 0; //HIGH
}
//*********有機ELキャラクタモード初期化関数********************
void OLED_Character_Ini(){ //OLED WS0100 初期化  
  PIN(OLED_RW_pin) = 1; //LOW
  PIN(OLED_E_pin) = 1; //LOW
  PIN(OLED_RS_pin) = 1; //LOW

  //OLEDリセット
  delayMicroseconds(10);
  OLED_CommandWrite(B00000001);//Display Clear
  delay(10);
  OLED_CommandWrite(B00010011);//Character MODE ON, Power is turned OFF
  delay(10); //リセットは一旦電源を切るべし
  OLED_CommandWrite(B00001000);//Display OFF, Cursor OFF, Brinking OFF 
  delay(1000);
  //ここからディスプレイ初期化設定
  OLED_CommandWrite(B00010111);//Character MODE ON, Power is turned ON
  delay(10);
  OLED_CommandWrite(B00111000);//Function Set 8bit-mode 2Line-display
  delay(10);
  OLED_CommandWrite(B00001111);//Display On, Cursor ON, Brinking on 
  delay(10);
  OLED_CommandWrite(B00000001);//Display Clear
  delay(10);
  OLED_CommandWrite(B00000010);//Return HOME
  delay(10);
  OLED_CommandWrite(B00000110);//Entry Mode Set, Increment, No-Shift
  delay(10);
}
//*********有機ELグラフィックスモード初期化関数********************
void OLED_Graphic_Ini(){
  PIN(OLED_E_pin) = 1; //LOW
  PIN(OLED_RW_pin) = 1; //LOW
  PIN(OLED_RS_pin) = 1; //LOW

  //OLEDリセット
  delayMicroseconds(10);
  OLED_CommandWrite(B00000001);//Display Clear
  delay(10);
  OLED_CommandWrite(B00010011);//Power is turned OFF, Character MODE ON
  delay(10); //リセットは一旦電源を切るべし
  OLED_CommandWrite(B00001000);//Display OFF, Cursor OFF, Brinking OFF 
  delay(1000);
  //ここからOLED初期化設定
  OLED_CommandWrite(B00011111);//Graphic MODE ON, Power is turned ON
  delay(20);
  OLED_CommandWrite(B00111000);//Function Set 8bit-mode 2Line-display
  delay(10);
  OLED_CommandWrite(B00001100);//Display On, Cursor OFF, Brinking OFF
  delay(10);
  OLED_CommandWrite(B00000001);//Display Clear
  delay(10);
  OLED_CommandWrite(B00000110);//Entry Mode Set インクリメント&シフトなし
  delay(10);
}
//*********電光掲示板風スクロール関数 8x16ドット 12文字用********************
void Scroller_8x16x12_Dot_Replace(uint8_t disp_char, uint8_t next_buff1[][16], uint8_t scl_buff1[][16], uint8_t* Orign_buff1, uint8_t font_buf1[][16], uint16_t Length, uint8_t* scl_cnt1, uint16_t* sj_cnt1){
  int8_t i, j;

  if(*scl_cnt1 == 8){
    *scl_cnt1 = 0;

    if(fnt_read_ok == true){
      Zen_or_Han = SFR.Sjis_inc_FntRead(sj_txt, sj_length, sj_cnt1, bufff);
      fnt_read_ok = false;
    }

    for(i=0; i<16; i++){
      Orign_buff1[i] = bufff[Zen_or_Han_cnt][i];
    }

    Zen_or_Han_cnt++;
    if(Zen_or_Han_cnt == Zen_or_Han){
      Zen_or_Han_cnt = 0;
      fnt_read_ok = true;
    }
  }

  for(i=15; i>=0; i--){ //まず、一番左側文字をビットシフト
    next_buff1[disp_char-1][i] = ( next_buff1[disp_char-1][i] | ( scl_buff1[disp_char-1][i] & B10000000 ));
    scl_buff1[disp_char-1][i] = scl_buff1[disp_char-1][i]<<1;
    scl_buff1[disp_char-1][i] = ( scl_buff1[disp_char-1][i] | (( Orign_buff1[i] & B10000000 )>>7));
    Orign_buff1[i] = Orign_buff1[i]<<1;
  }
  for(i=disp_char-2; i>=0; i--){ //次にその他文字をビットシフト
    for(j=15; j>=0; j--){
      next_buff1[i][j] = ( next_buff1[i][j] | ( scl_buff1[i][j] & B10000000 ));
      scl_buff1[i][j] = scl_buff1[i][j]<<1;
      scl_buff1[i][j] = ( scl_buff1[i][j] | (( next_buff1[i+1][j] & B10000000 )>>7));
      next_buff1[i+1][j] = next_buff1[i+1][j]<<1;
    }
  }
  (*scl_cnt1)++;
}
//*********有機EL 漢字フォント表示出力関数********************
void OLED_8x16x12_Font_DisplayOut(uint8_t len, uint8_t buf[][16]){
  uint8_t i, j, k;
  uint8_t Rbuf[len][16];

  for(k=0; k<len; k++){ //+90 Dot Rotation
    for(j=0; j<8; j++){
      for(i=0; i<8; i++){
        bitWrite(Rbuf[k][j], i,bitRead(buf[k][i], 7-j));
      }
    }
    for(j=8; j<16; j++){
      for(i=8; i<16; i++){
        bitWrite(Rbuf[k][j], i-8,bitRead(buf[k][i], 15-j));
      }
    }
  }

  for(j=0; j<len; j++){ //OLED Display OUT
    OLED_XYset(j*8, 0);
    for(i=0; i<8; i++){
      OLED_DataWrite(Rbuf[j][i]);
    }
    OLED_XYset(j*8, 1);
    for(i=8; i<16; i++){
      OLED_DataWrite(Rbuf[j][i]);
    }
  }
}
//*********有機EL XY設定関数******************************
void OLED_XYset(uint8_t x, uint8_t y){
   OLED_CommandWrite(0x80 + x);  
   OLED_CommandWrite(0x40 + y);
}
//*********有機EL 設定コマンド送信関数********************
void OLED_CommandWrite(uint8_t b){
  PIN(OLED_RS_pin) = 1; //1=LOW
  MCP23S08_SpiCommandWrite(b);
  PIN(OLED_E_pin) = 0;//EピンをHIGH→LOWへ変化させると書き込み完了
  PIN(OLED_E_pin) = 1;
}
//*********有機EL データ送信関数**************************
void OLED_DataWrite(uint8_t b){
  PIN(OLED_RS_pin) = 0; //0=HIGH
  MCP23S08_SpiCommandWrite(b);
  PIN(OLED_E_pin) = 0;//EピンをHIGH→LOWへ変化させると書き込み完了
  PIN(OLED_E_pin) = 1;
}
//*********GPIOエキスパンダMCP23S08コマンド設定関数*******
void MCP23S08_SpiCommandWrite(uint8_t b){
  PIN(MCP_CS) = 1; //1=LOW
    SPI.write(B01000000);
    SPI.write(0x0A);
    SPI.write(b);
  PIN(MCP_CS) = 0; //0=HIGH
}
//***************時計表示関数*****************************
void Clock_Display(uint8_t sec_or_ymd){
  String time_str;
  uint8_t time_sj_txt[25];
  uint16_t time_sj_length;
  char month_chr[3], day_chr[3], h_chr[3], m_chr[3], s_chr[3];
  const char* week_jp[7] = {"日","月","火","水","木","金","土"};
  uint8_t time_dot[12][16];

  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());

  if(now() != prevDisplay){ //ここから時刻表示設定
    switch(sec_or_ymd){
      case 0:
        time_str = String(h_chr) + ':' + String(m_chr) + ':' + String(s_chr) + '(' + String(week_jp[weekday()-1]) + ')';
        break;
      case 1:
        time_str = String(month_chr) + '/' + String(day_chr) + String(week_jp[weekday()-1]) + String(h_chr) + ':' + String(m_chr);
        sec_colon_time = millis();
        break;
    }
    clock_Disp_OUT = true;
    prevDisplay = now();
  }else if((millis()-sec_colon_time >= 500) && (sec_or_ymd == 1) && (clock_Disp_OUT == false)){
    time_str = String(month_chr) + '/' + String(day_chr) + String(week_jp[weekday()-1]) + String(h_chr) + ' ' + String(m_chr);
    clock_Disp_OUT = true;
  }
  if(clock_Disp_OUT == true){
    u8ts.UTF8_to_SJIS_str_cnv(time_str, time_sj_txt, &time_sj_length);
    SFR.SjisToShinonome16FontRead_ALL(time_sj_txt, time_sj_length, time_dot);
    OLED_8x16x12_Font_DisplayOut(DispChar, time_dot);
    clock_Disp_OUT = 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){
  memset(packetBuffer, 0, NTP_PACKET_SIZE);

  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
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}

(Web上でソースコードを配布する場合はライセンスを記述しなければ、自由に配布できないということですので、MITライセンスとしておきます。)

【解説】

前回の記事のスケッチと重複するところは省いて説明します。

●11-12行:
修正したライブラリのインクルードです。
ShinonomeFONTread は beta ver 1.40
UTF8toSJIS は beta ver 1.50
を使用してください。

●15行:
今回で使用する Arduino 標準の Timeライブラリ です。
時計表示に使用します。

●16行:
インターネット上のNTPサーバーから標準時刻を取得するためのWi-Fi UDP通信ライブラリです。
これはArduino core for Wi-Fiチップライブラリ標準のものです。

●23-24行:
xxxxのところをご自分のルーターの環境に合わせて書き換えてください。

●44行:
UTF8SJISライブラリ beta ver 1.50 を使う場合、ファイルハンドルをこのように設定してください。
他の文字列はNGです。

●46行:
電光掲示板に流す文字列の最大数を半角で800 としています。
1024 を超えると動作が不安定になります。
先にも述べたように、このプログラムではSRAMを多量に消費していますので、安定動作のためには800くらいが良いと思います。
因みに、Yahoo! RSS ニュースのトピックスでは多くて600文字弱なので、これで十分です。
しかし、トピックス以外の記事は半角で1500を超えるので、例外エラーとなり、動作しませんのでご注意ください

●56-63行:
インターネット上のNTPサーバーから時刻を自動取得して補正するための定義です。
これは、Arduino core for ESP8266 ライブラリの Arduino IDEサンプルスケッチにあるものをそのまま流用してます。

●110-141行:
スマホのブラウザに表示するHTMLタグのうち、body要素内のものをString文字列で定義してます。
ヘッダ部分はSPIFFSでアップロードした spiffs_01.txt に記述してあります。
これは従来の自作EasyWebSocketライブラリ関数と同じ使い方です。
ちょっとしたポイントとして、124-125行と128行で使用している fieldsetタグが使い勝手が良いのでおすすめです。
要するに複数のボタンを囲って表示させるときに便利です。

●153-154行:
ここでNTPサーバーから時刻を取得して、ESPr Developer ( ESP-WROOM-02, ESP8266 ) の内部時計を補正してます。
509-548行でも関数化していますので参照してみてください。
ちなみにこの辺はArduino IDE サンプルスケッチをそのまま流用しています。
150行目のdelay(1000); はNTP時計受信後の動作を安定させるために、少々時間が必要なためのものです。

●177-208行:
110-141行で設定した、スマホボタンのID文字列の頭文字を受信したら、時計表示を切り替えるフラグを立てます。
“Clock”  の ‘ C ‘ を受信したら clock_Select = 0 となり、時計の秒表示セットとなります。そして、OLED に表示されます。
“clock” の小文字 ‘ c ‘ を受信したら月日曜日表示となるフラグを立てます。
191-206行では、スマホ上のYahoo記事取得ボタンのうち、どのボタンが押されたかを検知して、フラグを立てます。
検知したら時計表示やテキストボックス送信フラグをfalse にするところがポイントです。

●209-225行:
スマホ上のテキストボックスから送信された文字列をOLEDに表示するものです。
前回の記事と同様です。

●232-236行:
ここを通過する度に、OLED ディスプレイの文字を1ドットずつ左へずらしていきます。
233行でSRAMメモリ上でドットをずらし、234行でOLEDに一気に表示させて塗り替えています。

●238-240行:
ここで、スマホの時計表示ボタンが押されたら OLED ディスプレイに時計表示するようにしてます。
235行の関数は、462-498行を見てください。

●242-246行:
ここで1時間(3600秒)毎にNTPサーバーから時刻を取得して補正してます。

●248-290行:
249行で10分毎に通過する設定をしています。
注意していただきたいのは、この時間が短すぎると相手サーバーに迷惑をかけてしまうので、十分長く時間を取ってください
ここでは、スマホのYahoo!記事取得ボタンが押されたら、ここで記事取得するURLを分類してます。
先にも述べましたが、Yahoo! RSS 記事はトピックストップ記事のみ有効です。
他の記事は文字数が多すぎて例外エラーが出てしまうので、ご注意ください。
261, 265, 269, 274行が、自作のEasyWebSocketライブラリで関数化したものを使ってます。
(※SSLサイト対応にしました。2017/12/09)
Yahoo! RSS サイトの記事のソースコードを見ると、title で区切られたところが欲しいので、それを抽出してます。
この関数の使い方は以下の記事で紹介してますので、参照してみてください。

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

ちなみに、天気予報では不要な文字列が多いので、275行のStringクラスの replace を使って消去してます。

●377-414行:
電光掲示板スクロールするための関数です。
ShinonomeFONTread ライブラリ 1.40 で新たに登場した関数です。
文字1文字スクロールする度にsj_cnt1 が自動で1つカウントアップするものです。
メモリ節約のために、文字1つ分スクロールされたら、フォントを読み込むようにしました。
ただし、スクロールはぎこちなくなります。
WiFiClientSecureライブラリを使うと、メモリを大幅消費するので、仕方ありません。

●472-507行:
ここは、OLEDディスプレイに時計表示するための関数です。
月日表示のときには、コロン(:)を0.5秒毎に点滅させることが意外と面倒でした。
そこでちょっと複雑になっています。

●510-548行:
これはNTPサーバー時刻取得用のArduino IDE サンプルスケッチそのままの流用です。

以上、スケッチのザットした説明でした。
細かく解説すると労力と疲労が半端ないので、この辺にしておきます。

4.コンパイル書き込み、実行

では、コンパイル実行してみてください。
先の動画のように表示されればOKです。

そして、スマホ側ではこんな感じに表示されますので、いろいろと操作してみてください。

ちなみに、Yahoo! RSS 記事取得ボタンを押したら、WebSocket通信は強制切断されます。
つまり、記事取得はHTTP通信で、WebSocket通信のようなリアルタイム双方向プッシュ通信とは異なるので、そういう方式にしてます。

(2017/12/18 追記)
ライブラリをアップデートし、SSL化した Yahoo! Japan RSS を取得できるようになりましたが、その分、メモリを節約せねばならなくなったため、文字スクロールがカクカクしてしまうのは仕方ありません。
ESP-WROOM-02 の上位版、ESP-WROOM-32 ( ESP32 )ならばかなり余裕があるので、そういう問題は起こりにくいと思います。
いずれにしても、SPIFFSから読み込むと速度が遅いので、microSDHCカードから読み込む方が格段に速くなりますね。

5.まとめ

以上で、ようやく理想の大きさのニュース記事取得電光掲示板ができました。

正直言って、これはいろいろと実用レベルで使えますよ!!!
いままで懸案事項だったタイマー機能を盛り込めば、介護などで薬の飲み忘れ防止掲示板なんかも作れそうです。
近々これ用のケースを作ってみたいと思ってます。

ただ、問題は、SRAMが一杯いっぱいだというところです。
SRAMの増設も検討するとか、グローバル変数領域のメモリをうまく節約するしかありません。

ということで、今回はここまでです。
ではまた・・・。

Amazon.co.jp 当ブログのおすすめ

スイッチサイエンス ESPr Developer 32 Type-C SSCI-063647
スイッチサイエンス
¥2,420(2024/03/28 13:45時点)
ZEROPLUS ロジックアナライザ LAP-C(16032)
ZEROPLUS
¥22,504(2024/03/27 20:02時点)
Excelでわかるディープラーニング超入門
技術評論社
¥1,700(2024/03/28 09:40時点)

コメント

  1. けんにぃ より:

    初めまして。いつも記事楽しく拝見させて頂いてます。
    今回電光掲示板を作成してみたのですが、スマホに画面表示ができません。スマホのブラウザにはIPアドレスの数字のみ入力すれば良かったんですね?
    お手数ですが、教えていただけますでしょうか。
    現在、時間の表示(IPアドレス修正済)とヤフーのニュースが表示できませんの文字がスクロールはしています。

    • mgo-tec mgo-tec より:

      けんにぃさん

      記事をお読みいただき、ありがとうございます。
      しばらく、ESP-WROOM-02 を動かしておらず、この記事も随分昔に書いたので、思い出すのに時間がかかってしまいました。

      この記事以降、最近では Yahoo RSS サイトが 完全SSL化してしまった為、WiFiClientSecureライブラリを使用せねば動かなくなりました。
      ただし、これを使うと、膨大な文字列処理の為にメモリーを多く消費してしまいます。
      (参照記事)
      Yahoo! RSSニュース 電光掲示板 のhttps ( SSL )化対策 ( ESP8266 SSD1306 編)

      そのため、ESP8266 ( ESP-WROOM-02 )ではSRAM が足りない可能性があります。
      記事のプログラムを修正してみましたが、安定動作はしませんのでご了承ください。
      変えたところは、44行目のMaxTxtを300にしました。
      これ以上にすると動作しない可能性があります。
      そのため、エンタメなどの文字列は長すぎて受信できずにクラッシュします。
      それと、NTPサーバーアドレスを Windows サーバーに変えました。
      また、257行目は SSL サーバー用GET関数に変えました。

      これでも途中でクラッシュしてしまうので、あとはご自分で工夫してメモリを節約してみてください。
      私の場合はとても忙しく、プログラムの大幅修正はできない状態です。
      申し訳ございません。
      m(_ _)m

      (余談)
      今、私は ESP32 に取り組んでいて、こちらの方が遙かにメモリが大きいので、それに乗り換えた方が良いかもしれません。
      ただ、このプログラムは動作しませんが・・・。

  2. けんにぃ より:

    お忙しい中、早速のご回答と対策までして頂き本当にありがとうございました。
    ヤフーニューストピックス表示出来ました☆
    ◆マークは何故か消えてしまいましたが、時間表示と文字は問題なく表示されています。
    ただ、スマホの画面は相変わらず表示出来ません。シリアルモニターに表示されたIPアドレスをブラウザに入力したのですが。スマホもアンドロイドで動作確認◎になっている機種です。
    spiffs_01.txtにIPアドレス記載してメモリにOTAで書き込みもしているのですが。var wsUri = ‘ws://192.168.X.XX’; ←Xにはシリアルモニタで表示された数字入れています。それ以外の必要なファイルも含め4つ合わせて同時書き込みでしています。
    ちなみに私はネットワークカメラや天気JSONデータの取得等でESP-WROOM-02でのスマホで操作の経験は少しあります。
    もし、何かこれ以外で原因と思われる事があればアドバイスがあればお願い致します。

    • mgo-tec mgo-tec より:

      けんにぃさん

      お返事遅くなりすみません。
      本業が忙しく、その他、ESP32の取組中の作業がありまして、なかなか検証が進んでいない状態です。

      Yahoo Japan RSS が SSL 化する前は問題無く動作したのですが、今、確実に分かることは、SRAMメモリーが確実に足りていないということです。
      特に、Arduino-ESP8266 の WiFiClientSecure ライブラリ関数を呼び出す度にメモリを食われるので、グローバル領域やスタック領域のメモリサイズをできるだけ小さくする必要があります。
      MaxTxt = 300 としても、まだ大きいと思われます。
      font_buf[MaxTxt][16] と、ブラウザに投げる html_str がかなりのメモリを消費してしまっているので、プログラムの大幅改善が必要です。

      今の取り組み中作業が終わり次第、改善したプログラムを記事に載せようと思っておりますので、しばらくお待ちください。

  3. けんにぃ より:

    ご連絡ありがとうございます。
    あれから色々テストしていたところ、どうもWebSocket通信が出来てないのが原因かもしれないです。
    他に書いておられる記事「WebSocket でスマホから Arduino化 WROOM のLEDを調光してみる」もテストしましたがスマホの画面表示されませんでした。繋がっていない表示が出てます。
    なのでメモリーだけの問題ではないかもしれませんね。
    私の方も引き続いて調べていますが、行き詰ってしまいそうです。
    お時間出来たらで結構ですので宜しくお願いします。

    • mgo-tec mgo-tec より:

      けんにぃさん

      WebSocket については、私のライブラリの場合は SSL通信ではなく、普通の HTTP 通信で行っています。
      ですから、もしかしたら、ルーターのセキュリティか、パソコンのセキュリティーソフトのファイアウォールに引っかかっているかもしれません。
      それと、ブラウザはGoogle Chrome でないと動作しませんのでご注意ください。
      Microsoft Edge や FireFox などは動作しません。

      それと、見当はずれかもしれませんが、Windows10 の場合、OS の「設定」画面の
      「ネットワークとインターネット」→「共有オプション」→「プライベート」→「ネットワーク探索」
      の中の
      「ネットワーク探索を有効にする」
      にチェックが入っているか確認してみてください。

      私の作った EasyWebSocketライブラリは、ローカルエリアネットワークの ESP8266 サーバーに接続していることと同じことなので、ネットワークの設定やブラウザ設定、ウィルス検出ソフト設定にかなり影響されます。
      最近のルーターでは、セキュリティーが強化されていて、デフォルトでローカルエリアのサーバーに繋がらない場合があります。

      また、WebSocket でSSL通信ができれば良いのですが、いつかその方法を実験しようと考えていますが、まだ実現できていません。

      ということで、私も今の課題が終了したら取り組みますので、しばらくお待ちくださいませ。
      m(_ _)m

  4. けんにぃ より:

    お世話になります。
    先程接続出来ました。ルーターの設定やwi-fiの設定いじってたら繋がりました。
    お騒がせしてすみません。
    ここで初めて容量に余裕がなく動作不安定というのが少しわかりました。◇マークも表示されています。

    • mgo-tec mgo-tec より:

      おー!
      つながって良かったです。
      あとは、残るはメモリの問題だけですね。

      • けんにぃ より:

        ありがとうございます☆
        文字大きくて見やすいし、これは感動ですね☆
        余裕あると思っていた02もこれだけの処理するといっぱいになるんですね。
        手動で文字表示がメインの使い方になるとは思いますが、ニューストピックスだけでも流れてると良い感じなので可能な限りで性能出せたら良いですね☆
        32は気になってますが、もう少し02で色々やってみたいなと思っています。

  5. けんにぃ より:

    こんにちは。
    EasyWebSocket(一般的なWebSocketも含む)ですが、外出先からスマホで接続する事は無理でしょうか?
    グローバルIPアドレスでポート転送をやってみましたが画面は表示されるもののWS接続は出来なかったんです。
    やりたいと思っている事は「入力した文字を表示させる」これだけの機能でも良いのですが、スマホで外出先から文字を入れて自宅で表示させたいと考えていいます。

    • mgo-tec mgo-tec より:

      けんにぃさん

      お返事遅くなりすみません。

      この記事のソースコードを大幅修正しました。
      そして、自作ライブラリをバージョンアップしました。
      ShinonomeFONTread beta ver 1.40
      Utf8SJIS beta ver 1.50

      メモリを節約するため、font_buf の配列を最低限に少なくし、1文字スクロールする度に SPIFFS からフォントを取得する方式に変更しました。
      それによって、エラーが無くなったと思います。
      ただし、スクロールはスムースでなくなり、多少ぎこちなくなるのは仕方ありません。

      SPIFFS は読み取り速度が遅いので、microSDHC カードから読み込んだ方が確実に速いですね。
      いずれにしても、私自身はもう ESP8266用の新たな開発はする予定はありません。
      とにかく、私的には ESP32 をお薦めしたいです。

      また、グローバルアドレスを使った通信は、EasyWebSocketライブラリではできません。
      VPN通信を使うとか、Firebase を使えば可能かもしれません。
      ただ、それでも、WebSocket を SSL化しなければいけないので、無理かもしれません。
      WebSocket の SSL化は来年の私の課題ですね。

      あとは、Blynkというアプリを使う方法です。
      https://www.mgo-tec.com/blog-entry-esp32-blynk-01.html
      https://www.mgo-tec.com/blog-entry-esp32-blynk-oled-ssd1331-01.html
      これで漢字が使えるかどうかわかりませんが、うまくやれば使えるかも知れません。

      以上ですが、私の過去のソースコードは、Arduino core for ESP8266 がアップデートしたり、他のWebサイトが変更なったりして、動かなくなる場合があります。
      私自身、本業の仕事や親の介護などもあり、その度にすべて変更することはとても無理ですので、基本的にすべて無保証とさせていただいております。
      ただ、ご連絡いただければ、空いた時間で、できるだけ対応したいとは考えておりますので、ご理解のほどよろしくお願いいたします。

  6. けんにぃ より:

    お忙しいところ対応頂きありがとうございます。
    ソースコードとライブラリ早速使わせてもらいました。
    私のは環境が悪いせいかカクカクが少し気になる感じでしたが、エラーはなくなりました☆ありがとうございます。
    グローバルアドバイスは使えないんですね。自分のやり方がまずいのかと思ってましたが、それで納得です。
    スマホで文字を入れたのを表示ですが、教えてもらったサービスや利用しているレンタルサーバーやクラウドサービスを駆使してなんとか出来ないかも試してみます。
    まだ全然知識ないのでアプリも作りたいのですが難しそうです。
    32もいよいよ購入検討してみたいと思います。
    なるべくお手間掛けないように自分で勉強しながら頑張りますが、ソースコードとかの内容で分からない時は聞かせてもらうかもしれませんが宜しくお願いします。

    • mgo-tec mgo-tec より:

      スクロールのカクカクは SPIFFS を使った場合、ESP32 でも起こるのですが、ESP32 の場合、デュアルコアなので、工夫次第ではスムースにできます。
      ただ、私も基本的に素人ですので、プログラムをもっと工夫すれば、デュアルコアを使わなくてもスムースにできると思います。
      私には知識がないので、今のところここまでが限界です。
      スムースにできるようになったら、いつか記事に上げたいと思っています。
      というわけで、今後とも当ブログをよろしくお願いいたします。

  7. けんにぃ より:

    お久しぶりです。
    現在自分なりに色々変更させてもらって、耳の遠い父親へのメッセージボードとしてすごく役立っており感謝してます。
    ガスコンロの炎監視して信号を受信してメッセージボードに注意メッセージを流す機能も追加予定しています。

    今やりたいですが、うまくいかず困っている事は、SSIDやpasswordを自動で取得するWi-Fiマネージャー等のオートパスを使い、スケッチに書き込みではなく、スマホからの入力で取得してEEPROM?に書き込み、二回目以降は読み込んで繋がるようにしたいと思っています。
    オートパスはこちらのも試していますが、スケッチにどう書き込めば上手く動くかがよくわかりません。
    http://eleclog.quitsq.com/2015/08/esp8266-wifi-setup.html?m=1
    もし、何か参考になる事があれば教えて頂ければ助かります。
    Websocketではなく、通常の通信であればオートパスはWi-Fiマネージャーで使えてます。
    ちなみに、スケッチは、最終改良する前のバージョンに戻して使ってます。

    • mgo-tec mgo-tec より:

      けんにぃさん

      ガスコンロの炎感知機能ができればスバラシイですね。
      それはいつかやってみたいと私も思っていました。

      SSID のスマホ選択については、最新の以下の記事で、ESP32 についてはやっています。

      ESP32のWi-Fiアクセスポイントをスマホで選択できるようにしてみた

      これを ESP8266 用に変換して使えば、ESP8266 でも問題無くスマホ選択できるようになると思います。
      ESP32_WebGet ライブラリは、ただ単にNTPサーバーから時刻を取得する為だけに使っているので、その関連コードは削除すれば良いと思います。

      オートパスについてはまだ見ていませんので良く分かりません。

      また、ESP32 では、純正で SmartConfig というライブラリがあり、スマホアプリと連動すれば、もの凄い簡単にスマホSSID選択ができるようです。
      これは、もともとESP8266用に書かれているのですが、最近 ESP8266 でテストしていないので、今のところ良く分かりません。

      ということで、他の仕事で手一杯で、検証する時間がありませんが、取り急ぎの返信です。

  8. けんにぃ より:

    早速のご返答ありがとうございます☆
    32の方でやられてたんですね!
    参考にさせて頂きます。本当に助かります。
    ガスコンロの炎監視に関しては、赤外線センサーや紫外線センサーでテストしましたが、ライターの炎は感知しても、ガスコンロ(うちは田舎なのでプロパンガスですが)の炎はほとんど感知出来なくて苦戦してました。
    値段は高くなりますが、下記のガラス管のセンサーと駆動ユニットでバッチリ感知するのを検証出来ました。
    出力は10usパルスなのですが、リレーが接続出来るみたいなので、時間出来たらテストしてみようと思います。
    http://eleshop.jp/shop/g/g27G135/

    • mgo-tec mgo-tec より:

      けんにぃさん

      面白い情報ですね。
      炎感知センサーはかなりイイ感じですね。
      これはいつか試そうと思いました。
      有益な情報、ありがとうございます。
      m(_ _)m

  9. けんにぃ より:

    こちらこそいつもありがとうございます。
    炎センサーは少し価格が高めなので、買う前にメーカーに電話してガスコンロの炎感知出来るか聞いたのですが、可能だと思うが未検証で確約出来ないとの返事で、少し冒険でしたが結構感度良く満足です。
    SSIDの件ですが、これでWi-Fi接続した場合にEasyWebsocketにそのまま接続出来るのでしょうか?
    EasyWebsocketのIPアドレスws…はファイルに書き換え
    「大きめドットの…」の3つのファイル+今回のパス書き込み用の空テキストファイル書き込みした上でですが。

    • mgo-tec mgo-tec より:

      けんにぃさん

      お返事おそくなり、すみません。
      ESP8266用のEasyWebSocketライブラリは、独自にWi-Fi接続関数を組んでいるため、ライブラリを改変していただくしかありません。
      ESP32 用のライブラリでは、Wi-Fi接続関数を独立させましたので、そちらを参考に改変してみてください。
      恐らく、Wi-Fiに接続できれば、問題無く Websocket も接続できると思われます。
      試していませんが・・・。
      今は別の課題に取り込み中で、当方では ESP8266 を改変する時間が全くありません。
      申し訳ございません。

  10. けんにぃ より:

    お忙しい中ご返答ありがとうございます☆こちらこそいつもすみません。
    内容了解しました。色々試してみますね。

  11. けんにぃ より:

    こんにちは。
    お忙しいところすみません。
    可能ならで結構なんですが、Websocketでスマホの画面でボタン押す操作をせず、ESPのスケッチで擬似的にボタンを押したのと同じ動作をさせるにはどうしたら良いのかわからず困っています。
    例えば、Websocketの通信切れた場合に再接続ボタン押す、ヤフーの4つある選択を切替するボタンを押すなどですが、ESPがどこでそのボタン操作したのを受けているかよくわからないんです。
    やりたいのは、外部サーバーに接続しに行くので、毎回Websocketが切断される為、その都度再接続ボタンを押した状態にする、センサーからの外部信号を受けたらヤフーのチャンネル切替するというものです。

    ボタンを押した場合、どこで信号出しているのか?どこで受けているのか?が解ればなんとかなるかも?と思っていますので、可能であれば教えて下さい。宜しくお願いします。

    • mgo-tec mgo-tec より:

      けんにぃさん

      いつもコメントありがとうございます。

      どういう動作にされたいのか、私自身あまり良く読み取れていないのですが、Websocket通信は ESP8266 サーバー側からクライアントのスマホへ接続することはできないと思います。
      スマホブラウザ側からのリクエストのみの対応です。

      スマホのボタンが押された場合、WEBページの JavaScript で ESP8266 へテキスト情報を送信しています。
      それは、HTMLヘッダファイル spiffs_01.txt に記載されています。

      また、Websocket は常時強制接続向きの通信ではありません。
      あったとしても、いろいろとセキュリティ上望ましくないため、その方法を調べたことはありません。
      SSL通信の Websocket ならば良いかもしれませんが、常時接続の方法は知りません。

      ただ、ESP8266 が読み取ったセンサー値によって、スマホ操作とは関係なく Yahoo ニュースの記事を切り替えることはできます。
      この記事でいえば、センサーが読み取ったら、24行目で Web_first_get が true になっていれば、記事を取得しに行きます。
      Yahoo_get の番号をその記事に対応させればよいです。

      因みに余談ですが、ESP32 の EasyWebsocket では HTTP のYahoo記事 GET しても Websocket が切断されないようになっています。

      あともう一つ、こちらの記事でもお知らせしていますが、最新版 Arduino-ESP8266 ver 2.4.1 にして、Crystal Frequency を 26MHz にするとバッチリ動いて、処理速度もちょっと速くなります。
      Wi-Fi WPA2 脆弱性も対策済みなので、おすすめです。

  12. けんにぃ より:

    ご返答どうもありがとうございます。

    スマホボタン押した場合の情報はspiffs_01.txtを確認すれば良いのですね。確認してみます。

    センサー値によりヤフー記事の切替が出来ればやりたい事の半分解決ですが、24行目のWeb_first_getというのがWeb_first_getが沢山あり、どれかわかりませんでした。

    ESP32はこの件を8266で解決してから切替を予定していますが、
    Arduino-ESP8266 ver 2.4.1 はすごく興味があるので試してみます。
    情報すごくありがたいです。

    • mgo-tec mgo-tec より:

      けんにぃさん

      すみません、言い忘れたことがあります。
      スマホボタンのしくみは、spiffs_01.txt はHTMLヘッダですので、それだけでは理解が難しいかと思います。
      スマホに表示された WEBページの HTML ソースを全部見た方が良いと思います。
      例えば、IPアドレスが、192.168.0.14 の場合で、Google Chrome の場合は、URL欄の先頭に、

      view-source:192.168.0.14
      

      と入力するとソースをみることができます。

      Websocket のボタン送信のやり取りの仕組みは以下の記事を参照してください。
      Arduino化 WROOM で WebSocket データ送受信方法

      また、Web_first_get は、グローバル変数なので、関数のどこからでも true に変えれば、HTTP GET されると思います。

      • けんにぃ より:

        早速のご返答ありがとうございます。
        私は本当に詳しくないもので、仕組み教えて頂けてすごく助かりました。
        これから早速見てみます。
        お忙しい中ありがとうございました。

  13. けんにぃ より:

    早速のご返答ありがとうございます。
    私は本当に詳しくないもので、仕組み教えて頂けてすごく助かりました。
    これから早速見てみます。
    お忙しい中ありがとうございました。

  14. けんにぃ より:

    先日教えて頂いてから色々やってみて、
    おかげさまでESPのピンのHigh Lowでヤフーの記事切替は出来ました。

    あと、どうしてもわからなかったのが、スマホでRe-connectボタン押した時にOnclickでInit()が出力される??
    ESPで受けてるのは、cppファイル?
    受けてから実際に動作させているのは、下記の部分?

    switch(ws)
    { case 1: _WS_on = true; break; case 2: _WS_on = false; break; } switch(ini_htm){ case 1: _Ini_html_on = true; break; case 2: _Ini_html_on = false; break; } switch(up_f){ case 1: _Upgrade_first_on = true; break; case 2: _Upgrade_first_on = false; break; }

    やりたい事は、
    ヤフーの記事を切替えるとconnectの切断ボタンを押した時と同じような切断状態になってしまうので、切替操作した後に連動させて(わずかなディレイを入れてから?)Re-connectさせたいものです。

    connect切断されるのは、ヤフーのメイン記事(1Yahoo)に切替して回線まで切断するような状態ではなくて、ハンドシェイクのみ?切れてしまうので、その後の切替がスマホで出来ない為、なんとかしたいものです。

    なんとか自力でやりたいのですが、どうも解決出来なさそうな感じなので、出来ればアドバイス頂けたら助かります。
    お忙しいところ申し訳ありませんが、宜しくお願いします。

    • mgo-tec mgo-tec より:

      けんにぃさん

      取り込み中の作業があり、お返事遅くなりすみません。

      ESP8266 の場合のライブラリはまだ更新していなかったので申し訳ないのですが、EasyWebSocket ライブラリ中で client を切断しているので websocket が切断されます。
      それに合わせてスマホブラウザ側でも切断するようにしています。
      ですから、再接続されたい場合は、スマホ側の HTML および Jabascript で delay をかけて自動再接続するようにプログラムするしか現状ではお答えできません。
      ここでは詳しくは申し上げられないのですが、Javascript で new Date().getTime() を用いて delay 関数を作るという方法があると思います。
      ネットでは、時間差でアクセスするような方法が沢山ありますので、調べてみて下さい。

      近々、切断されないようにライブラリを変更しようと考えていますのでしばらくお待ちください。

    • mgo-tec mgo-tec より:

      けんにぃさん

      久々に ESP8266 を動かして、いろいろやってみましたが、HTTP GET するとどうしても Websocket は切断されるようです。
      ESP8266 のserverポート番号を443にしても切断されてしまいます。
      ライブラリ中の client.stop() を削除しても切断されてしまいます。
      恐らく、ブラウザがそういう仕様なのだと思うので、ライブラリの変更は諦めました。

      そういえば、1~2年前もESP8266でそれができないかいろいろ試行錯誤した記憶があり、結局できませんでした。
      Websocket は暗号化されてないポート番号80で通信していて、Yahoo記事を取得する時は 443ポートを開きます。
      それが同じポート番号にしても切断されるということは、WebsocketプロトコルとHTTPプロトコルの同時使用はブラウザが許してくれないのかも。
      ESP32では可能だと思っていたのですが、ESP32でもできないかもしれません。
      以前できたと思っていたのですが、時間がある時にもう一度再検証してみます。

      ということで、スマホブラウザ側のJavascript で遅延させて再接続するプログラムを組んだ方が良さそうです。
      また何か分かり次第お知らせします。

  15. けんにぃ より:

    ご返答ありがとうございます。
    client を切断しているという事なんですね。
    教えて頂いた方法を調べてみます。

    とはいえ、私の知識では解決出来るか自信なく
    arduinoのスケッチの知識もですが、HTML や Jabascriptに
    関しては全然解ってないもので
    ライブラリの変更もお忙しい中すみませんが宜しくお願いします。

    私自信もっと勉強しないといけないと痛感していますが、
    なかなか調べても理解が出来なくお恥ずかしい限りです。

  16. けんにぃ より:

    今メッセージ送らせて頂いてから気付いたのですが、追加でメッセージ頂いてたのですね。
    お忙しい中、ESP8266でテストまでして頂いてどうもありがとうございます。
    ライブラリの修正でなくても、Javascript で遅延させて再接続
    いう方法で全然問題ないので調べてみます。

    • mgo-tec mgo-tec より:

      今、ESP32搭載のM5stackに集中していて、近々、久々にWebsocket通信にも取り掛かる予定です。
      その時に再接続関係も調べる予定です。

      • けんにぃ より:

        M5stackすごく気になってます。

        その時は再接続何かわかりましたら宜しくお願いします。

        • mgo-tec mgo-tec より:

          はい、しばらく時間がかかると思います。

          • mgo-tec mgo-tec より:

            けんにぃさん

            やっと解明しました!
            ライブラリをほんのちょっと修正しただけで、Web_Get しても Websocket 通信が切断されなくすることができました。
            ESP8266 の SPIFFS 用 EasyWebSocket ライブラリだけ修正しています。

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

            これを使ってみて下さい。
            ESP32のライブラリで問題無くできていて、なぜ ESP8266 で出来ないんだろうといろいろと実験してみましたが、
            EWS_https_Web_Get function 関数
            の中で、最初に client.stop() をかけて切断しているところを削除し、その関数内の

            _WS_on = false;
            _Ini_html_on = false;
            _Upgrade_first_on = false;
            

            のところは不要だったので削除しました。
            ESP32 ライブラリでは既に削除していたのに気づかなかったのです。

            因みに、SDカード用は直しておりませんが、いずれ更新したいと思います。
            また、https 用の関数だけしか修正していません。

            以上、これでこの件は一件落着にできますか?

  17. けんにぃ より:

    早速やって頂きありがとうございました。
    休みに入ってじっくりやろうと思っていたら風邪を引いたのか熱が出て先程まで寝込んでおり気付くの遅くなりました。

    ライブラリを入れかえたところ、切断されず使える様になり大満足です。
    はい、これで一件落着です。本当に色々ありがとうございました。
    これで炎センサーでのガス監視もディスプレイに表示させてみようと思います。

    • mgo-tec mgo-tec より:

      えー! それはエライことでしたね。
      折角の休みがつぶれちゃいますね。
      私も連休に入ってちょっと体調崩し気味で、気を付けたいと思います。
      早く完治するといいですね。

      ライブラリ、無事動作して良かったです。
      探ってみると単なる盲点で、私のライブラリが原因でした。
      失礼しました。
      m(_ _)m
      ただ、ご存知だと思いますが、WebSocket はある程度時間が経つと、スマホ側から自動切断されます。

      ではでは、これからも当ブログをよろしくお願いいたします。
      どうぞご自愛くださいませ。

  18. けんにぃ より:

    いつもお世話になります。
    以前教えて頂いた、
    最新版 Arduino-ESP8266 ver 2.4.1 にして、Crystal Frequency を 26MHz にする
    というのを以前にやってみたのですが、ヤフー記事の切替(実際にはヤフー記事ではなく自分のサーバーに書き込んだメッセージの切替)
    をした時に、切替の反応が遅く、5秒前後(もっと長い場合もある)かかってしまうので2.3に戻していたのですが、昨日より自分の使用しているサクラサーバーがTLS1.2でないと繋がらなくなってしまった為、再度2.4.1にしてみたのですが、やはり切替に時間かかってしまいます。Arduino15のフォルダも消してみても変わらずでした。

    このバージョンはこんなものなのでしょうか?それとも何か原因があるのでしょうか?
    2.4.0でも切替に時間かかりました。2.3.0に戻すと今まで通りすぐ切替出来ます。

  19. けんにぃ より:

    あ、すみません訂正です。
    2.3に戻したら切替早くなったのは、以前テストした時の事です。
    現在は、2.3に戻すとhttpsでサクラサーバーに繋がらなくなります。

    2.4.1で切替速度が遅くなるのは仕方ないのであれば、2.3に戻してhttpsからhttpに戻したいのですが(ヤフー記事は使用せず、サクラサーバーに書き込みしたコメントのみ使用する)その場合どこを変更すればよかったでしょうか?

    • mgo-tec mgo-tec より:

      けんにぃさん

      ご無沙汰いております。
      また、このブログにお越しいただきありがとうございます。

      さくらサーバーは使ったことが無いので良く分からないのですが、サーバーとのhttp通信は近い将来廃止される可能性が高いので、httpsで通信した方が良いと思います。
      https 通信になると、Arduino – ESP8266 は WiFiClientSecure ライブラリを使うことになります。
      すると、SSL証明書や秘密鍵のやりとりをするために、最初の WebGet は http よりは遅くなります。

      その暗号化処理で、ESP8266 の処理速度も関係してきますので、クロック周波数は 160MHz にしていてもやはり多少が時間がかかると思います。
      また、さくらサーバー側の問題で、SSL通信に限って鍵のやり取りなどの問題でレスポンスが遅くなっている可能性も考えられます。
      サーバーによって異なりますが、読み取りだけならばルートCA証明書不要の場合もあります。
      (Yahoo RSSでは、現時点ではCA証明書不要です)
      その他は正直良く分かりません。

      いずれにしても SSL 通信はこの先必須になってきます。
      個人的には、SSL通信を使うには ESP8266 では辛いと思われますので、ESP32 にした方が良いと思われます。

      • けんにぃ より:

        ご返事ありがとうございます。
        httpいづれか廃止になる可能性あるならhttpsにしておくのがいいですね。
        ついに8266では限界がきたという事ですね。32に変更したいと思いながら、少し大変そうだなと、なかなか手を出せませんでしたが、やるしかなさそうですね。
        父親に作成したメッセージボードはバージョンアップさせて切替速度遅くなってもとりあえず使用してみます。

        • mgo-tec mgo-tec より:

          そうですね。
          限界だと思われます。
          お役に立てず、スミマセン。
          m(_ _)m

          • 匿名 より:

            いえいえ、色々教えて頂いて感謝でいっぱいです。
            ESP32の記事も参考にさせて頂きながら進めていきたいと思います。

  20. 匿名 より:

    さくらサーバーで記事切替時に時間がかかる件ですが、原因わかりました。
    読み込むフォルダ(ファイル)によって速かったり遅かったりするので調べたところ、ファイルの改行コードがLFだと速く切り替わりますが、LF+CRとなっていると遅いというのがわかりました。
    現在使用しているものについては、これで当分使えそうです。

  21. mgo-tec mgo-tec より:

    管理人の mgo-tec です。
    緊急連絡!!!
    2019/1/5 早朝にお問い合わせ欄でご連絡いただいた方へ。
    返信しても届かず、メールが返ってきてしまいます。
    再度、正しいアドレスでご連絡くださーい!!!

    • mgo-tec mgo-tec より:

      もしくは、そちらのメールサーバーがいっぱいで受信できない可能性もありますので、調べてみて下さーい!!!

タイトルとURLをコピーしました