Twitter 検索結果のツイートを有機EL ( OLED )に表示させてみた( ESP-WROOM-02 ( ESP8266 )、SSD1351 使用)

ESP8266 ( ESP-WROOM-02 )
※この記事を書いた当初のESPr Developer(ESP-WROOM-02)のFLASHサイズは4MBでした。
しかし、現在のESPr Developerおよび、ESP-WROOM-02 のFLASHサイズは2MBのものが流通しています。
その場合、東雲フォントなどの1MB以上の大きいサイズのファイルは SPIFFS へアップロードできませんのでご注意ください。
FLASHサイズの調べ方は以下の記事を参照してください。
ESP-WROOM-02 ( ESP8266 ) チップ・メモリ・MACアドレス情報確認方法
(2018/06/22)

 

こんばんは。

今回はちょっとスゴイことに挑戦してみました。
今までずっと思っていたのは、Twitter ( ツイッター ) の検索ってとても便利だなぁと思ってました。
というのは、Google や Yahoo 検索よりも、もの凄くリアルタイムの声がアップされるんですね。
ですから、仕事中などで野球や相撲などの結果をすぐに知りたい場合はツイッター検索かけると誰かが必ずツイートしてくれて、すぐに結果を知ることが出来ます。
その他、忘れてはいけないのは、3.11大震災や熊本地震などでツイッターはかなり活躍していました。
3.11の時はパソコンを開かずに最新ツイートを常時表示してくれるものがあれば便利だなぁと思っていました。

スポンサーリンク


そこで、今回はWi-Fi モジュールのESP-WROOM-02 ( ESP8266 ) と 16-bit フルカラー有機ELディスプレイ ( OLED ) SSD1351 を使って Twitter 検索結果の ツイートを表示させてみることに挑戦してみました。 ツイートは3分毎に更新しますが、何しろ画面が小さいので、一度に表示できるツイート数は限られます。

そして、今回の新たな挑戦として、Secure なWebページ、つまりSSL化したページ( https://で始まるページ )を取得するためのGETリクエストおよびレスポンスです。Twitter は全てSSL化されています。
最近ではGoogleがSSLページを推奨していて、かなりのWebページがSSL化しているようです。一般のブログなどでもSSL化されてくるでしょう。これからは必須アイテムです。
SSLは通信するときに暗号化されるので、通信途中で情報を盗まれる危険性が減ります。
私も、このブログを立ち上げたころからSSL化には注目していて、当ブログでも去年SSL化しましたが、その時はいろいろと設定が大変でしたね。

因みにSSLページ用のライブラリは、Arduino core for ESP8266 WiFi Chip ライブラリに標準装備されていて、サンプルスケッチもありましたので、それを参考にしました。
これがあったおかげで、結構簡単にTwitterページを取得できました。でも、実は取得までは簡単にできても、そこから欲しいテキストを抽出するのが大変なんです。Twitterのページのソースコードを見ていただくと分かるのですが、かなりいろいろなHTMLタグやスクリプトがあり、途中に超長い1行があったりして、普通に取得するとすぐにオーバーロードしてしまいます。そこからターゲットのテキストを抽出するのにはかなり工夫が必要で、相当苦労しました。
それに、検索語句を日本語にしてGETリクエストするときにUTF-8文字コードをパーセントエンコードしなければいけないんです。URL入力欄に入力するのと同じ形式です。その関数も自作せねばなりませんでした。

ということで、こちらの動画をご覧ください。
ツイッター検索のキーワードとして、話題のメタルグループ BABYMETAL にしてみました。

別のキーワードとして、イチローにしてみました。

いかがでしょうか。
GET取得したツイートを一気に8列表示させて、1行ずつスクロールさせています。
ツイートをできるだけ多く早く見る方法は他にもあったのですが、せっかくスクロールする関数を作ったので、今回はこれにしてみました。
そして、1ページ表示終わった後、色を変えてもう一度同じツイートをスクロールしていきます。
3分後に再びTwitterへGETリクエストしてツイートを取得するとまた色が変わります。
色を変えなくてもいいのですが、お遊びで変えてみました。

今回は正直言ってまだ実験段階の未完成なところがあります。
ツイートを取得中にフリーズして動かなくなってしまうときがあります。
その原因が実はなかなかつかめないでいます。
もし、何か分かる方がいらっしゃったら教えていただきたいです。

1.使うもの

前回の記事と同様ですが、初めてこの記事を読む方の為に念のため説明しておきます。

●ESPr Developer ( ESP-WROOM-02 開発ボード ( ESP8266チップ使用 )) スイッチサイエンス製

Arduino IDEで開発できる日本の電波法をクリアした技適認証済みWi-Fiボードです。
ESP-WROOM-02 ( ESP8266チップ使用 ) にUSBシリアルモジュール、電源レギュレーター等がパッケージされたとても使いやすいボードです。
Arduino UNO よりも高速処理、Arduino Mega以上のSRAM、4MバイトのSPIフラッシュメモリ付きという全部込みの優れものボードです。
Amazon.co.jp

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

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

Amazonさんでは在庫切れの場合がありますのでご注意ください。
スイッチサイエンスさんのページでも直販しておりますのでそちらもご覧ください。
このボードの使い方は次のページにありますのでご参照ください。
ESPr Developer ( ESP-WROOM-02 開発ボード )の使い方をザッと紹介

以下のボードも構造やGPIOピンは同じですので使えると思います。
(※ESPr One はAmazonで販売されなくなったようです。以下のリンクはが販売元です。
ESPr® One(Arduino Uno同一形状 ESP-WROOM-02開発ボード)

Adafruit OLED Breakout Board – 16-bit Color 1.5″ w/microSD holder

ちょっとお値段が高いのですが、色が16bitで指定できるので様々な中間色で表示することができます。SSD1306のようなOLEDでは8bit毎のページという表示設定がありましたが、このディスプレイドライバ SSD1351 は自由にピクセルを指定できます。
そして、何よりうれしいのが、microSDカードホルダー付きなので、SPI信号で読み書きできます。
スイッチサイエンスさんウェブショップにあります。
https://www.switch-science.com/catalog/1754/
これの組み立て方や使い方は以下のページを参照してください。

Adafruit 16-bit フルカラー OLED ( SSD1351 ) を ESPr Developer ( ESP-WROOM-02 ) で動かしてみた

ESP-WROOM-02 ( ESP8266 ) で Adafruit OLED ( SSD1351 )をライブラリ無しで使う方法を解説

●ブレッドボード、ジャンパーワイヤー、USBケーブル、PC等

2.接続、Arduino IDE 設定、ライブラリインストール、SPIFFSファイルアップロード

前回の記事の2~5番までの設定を予め済ませておいてください。
※SSD1351ライブラリは現在、Beta ver 1.53 (2016/10/18現在) になっていて、これをインストールしてください。このバージョンでSPI高速化が実現できて、スクロールスピードが2~3倍速くなりました。
インストールする際には予め古いバージョンのライブラリフォルダは削除しておいてください。
今回使う自作ライブラリのバージョンは以下の通りです。未だにベータバージョンでスイマセン・・・。
OLED_SSD1351  Beta ver 1.53
ShinonomeFONTread   Beta ver 1.31
UTF8toSJIS  Beta ver 1.3

また、SPIFFSファイルシステムアップローダーで予めアップロードしておくファイルは以下のファイルです。全体で1.34Mbくらいありますので、OTAでアップロードする形になると思います。

shnmk16.bdf  (全角東雲フォントファイル)
Shnm8x16r.bdf  (半角東雲フォントファイル)
Utf8Sjis.tbl  ( UTF-8 → Shift_JIS 文字コード変換テーブル )

3.スケッチを入力

申し訳ないのですが、今回は途中でフリーズすることがあるスケッチですので、予めご了承ください。無保証です。
Arduino core for ESP8266 WiFi Chipライブラリを使用していて、サンプルスケッチを改変していますので、ライセンスはLGPL ver2.1です。
【ソースコード】 (※無保証 ※PCの場合、ダブルクリックすればコード全体を選択できます)

/*
 * This Sample Scketch is part of the esp8266 core for Arduino environment.
 * Copyright (c) 2016 mgo-tec.
 * 
 * ESP8266WiFi.h - Included WiFi library for esp8266
 * Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
 * 
 * WiFiClientSecure.cpp - Variant of WiFiClient with TLS support
 * Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
 * 
 * Released under the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1
 * Reference LGPL-2.1 license statement --> https://opensource.org/licenses/LGPL-2.1
 */

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <UTF8toSJIS.h>
#include <OLED_SSD1351.h>
#include <ShinonomeFONTread.h>

UTF8toSJIS u8ts;
ShinonomeFONTread SFR;
OLED_SSD1351 ssd1351;
WiFiClientSecure client;

const uint8_t sclk = 14;
const uint8_t mosi =13;
const uint8_t cs = 15;
const uint8_t DCpin =  4;
const uint8_t RSTpin =  5;

const char* ssid = "xxxx";
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* host = "twitter.com";
const int httpsPort = 443;
char* search_str = "babymetal";

enum { MaxTxt = 300, MaxTwitDisp = 8};

uint8_t get_sjis[MaxTwitDisp][MaxTxt];
uint16_t Pgh; //ツイッターの投稿数
uint16_t sj_length[MaxTwitDisp]; //Shift_JISコードの長さ
uint8_t font_buf[MaxTxt][16];
uint8_t SnnmDotOut[16][16];
uint8_t Next_buf[16][16];
uint8_t dummy_font_buf[16];
uint8_t test_tmp_buf1[16], test_tmp_buf2[16];
uint16_t SclSpeed = 0;
uint32_t SclTime;
uint16_t sj_cnt = 0;
uint8_t scl_cnt = 0;
uint8_t twit_cnt = 0;

uint32_t WebGetTime;

uint8_t scl_col_cnt = 0;

void setup() {
  Serial.begin(115200);
  uint16_t i, j;
  uint16_t Len;
  
  ssd1351.SSD1351_Init(sclk, mosi, cs, DCpin, RSTpin);
  
  delay(300);

  ssd1351.SSD1351_BlackOut(); //黒画面出力
  //セットアップで全角を一旦表示させることが重要。半角だとなぜかSPIFFSファイル読み込みエラーになってしまうため。
  u8ts.UTF8_to_SJIS_str_cnv(UTF8SJIS_file, "WAIT・・・・", get_sjis[0], &Len);
  SFR.SjisToShinonome16FontRead_ALL(ZenkakuFontFile, HalfFontFile, 0, 0, get_sjis[0], Len, font_buf);
  uint8_t Red = 31, Green = 63, Blue = 31; //とりあえず最大値を指定
  ssd1351.SSD1351_8x16_DisplayOut_1col_LtoR(0, 0, Red, Green, Blue, Len, font_buf);
  
  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;
    }
  }

  WiFi.begin(ssid, password);
  Twitter_https_Get(UTF8SJIS_file, search_str, "/body", "js-tweet-text tweet-text\" lang=\"ja","<a href", "◆", get_sjis, sj_length, &Pgh);
  Red = 0; Green = 0; Blue = 31;
  
  for(int ii=0; ii<MaxTwitDisp; ii++){
    for(i=0; i<sj_length[ii]; i++)  Serial.write(get_sjis[ii][i]);
    Serial.println();
    if(ii<MaxTwitDisp){
      SFR.SjisToShinonome16FontRead_ALL(ZenkakuFontFile, HalfFontFile, 0, 0, get_sjis[ii], sj_length[ii], font_buf);
      ssd1351.SSD1351_8x16_DisplayOut_1col_LtoR(0, ii*16, Red, Green, Blue, sj_length[ii], font_buf);
    }
  }

  Serial.println(F("=========="));
  Serial.println(F("closing connection"));
  SclTime = millis();

  SFR.SjisToShinonome16FontRead_ALL(ZenkakuFontFile, HalfFontFile, 0, 0, get_sjis[0], sj_length[0], font_buf);
  for(i=0; i<16; i++) dummy_font_buf[i] = font_buf[16][i];
  for(i=0; i<16; i++){
    for(j=0; j<16; j++){
      SnnmDotOut[i][j] = font_buf[i][j];
    }
  }

  scl_cnt = 0;
  twit_cnt=0;
  sj_cnt = 16;
  WebGetTime = millis();
  SclTime = millis();
  
}

void loop() {
  int16_t i, j;
  uint8_t Red, Green, Blue;

  if(millis() - SclTime > SclSpeed){ //SclSpeed=0がスクロールの最速
    if(scl_cnt == 8){
      scl_cnt = 0;
      sj_cnt++;
      if(sj_cnt >= sj_length[twit_cnt]){
        sj_cnt = 16;
        twit_cnt++;
        if(twit_cnt == MaxTwitDisp){
          twit_cnt=0;
          scl_col_cnt++;
        }
        SFR.SjisToShinonome16FontRead_ALL(ZenkakuFontFile, HalfFontFile, 0, 0, get_sjis[twit_cnt], sj_length[twit_cnt], font_buf);
        for(i=15; i>=0; i--){ //インクリメントよりデクリメントの方が処理が速いらしい。
          for(j=15; j>=0; j--){
            SnnmDotOut[i][j] = font_buf[i][j];
          }
        }
      }
      for(i=15; i>=0; i--) dummy_font_buf[i] = font_buf[sj_cnt][i];
    }

    ssd1351.Scroller_8x16Dot_Replace(0, Next_buf, SnnmDotOut, dummy_font_buf); //文字ピクセルを1ピクセルずらすライブラリ関数

    switch(scl_col_cnt){
      case 1:
        Red = 0; Green = 63; Blue = 0;
        break;
      case 2:
        Red = 31; Green = 31; Blue = 0;
        break;
      case 3:
        Red = 31; Green = 0; Blue = 31;
        break;
      default:
        Red = 31; Green = 63; Blue = 31;
        break;
    }
    ssd1351.SSD1351_8x16_DisplayOut_1col_LtoR(0, twit_cnt*16, Red, Green, Blue, 16, SnnmDotOut);
    scl_cnt++;
    SclTime = millis();
  }

  if(millis() - WebGetTime > 180000){
    Twitter_https_Get(UTF8SJIS_file, search_str, "/body", "js-tweet-text tweet-text\" lang=\"ja","<a href", "◆", get_sjis, sj_length, &Pgh);
    Serial.println();

    if(Pgh > 0){
      for(int ii=0; ii<MaxTwitDisp; ii++){
        for(i=0; i<sj_length[ii]; i++)  Serial.write(get_sjis[ii][i]);
        Serial.println();
        if(ii<MaxTwitDisp){
          SFR.SjisToShinonome16FontRead_ALL(ZenkakuFontFile, HalfFontFile, 0, 0, get_sjis[ii], sj_length[ii], font_buf);
          ssd1351.SSD1351_8x16_DisplayOut_1col_LtoR(0, ii*16, 0, 0, 31, sj_length[ii], font_buf);
        }
      }
      SFR.SjisToShinonome16FontRead_ALL(ZenkakuFontFile, HalfFontFile, 0, 0, get_sjis[0], sj_length[0], font_buf);
      for(i=0; i<16; i++) dummy_font_buf[i] = font_buf[16][i];
      for(i=0; i<16; i++){
        for(j=0; j<16; j++){
          SnnmDotOut[i][j] = font_buf[i][j];
        }
      }
      scl_cnt = 0;
      twit_cnt=0;
      sj_cnt = 16;
    }else{
      Serial.println(F("GetTwitter is failed"));
    }

    scl_col_cnt++;
    if(scl_col_cnt > 4){
      scl_col_cnt = 0;
    }
    
    WebGetTime = millis();
    SclTime = millis();
  }
}
//***********************Twitter 検索語句からツイートを8つ取得*********************************************
void Twitter_https_Get(const char* UTF8SJIS, char* SearchStr, String Final_tag, String Begin_tag, String End_tag, String Paragraph, uint8_t sjis[][MaxTxt], uint16_t sjis_length[21], uint16_t* TwitCount)
{
  String twit_url1 = "/search?f=tweets&vertical=default&q=";
  String twit_search = StrPerEncord(SearchStr); //UTF8文字列をURLパーセントエンコードする関数呼び出し
  String twit_url2 = "&src=typd";
  
  uint32_t TimeOut = 0;
  
  Serial.println();
  Serial.print(F("connecting to "));
  Serial.println(ssid);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println(F("WiFi connected"));
  Serial.println(F("IP address: "));
  Serial.println(WiFi.localIP());

  Serial.print(F("connecting to "));
  Serial.println(host);
  if (!client.connect(host, httpsPort)) {
    Serial.println(F("connection failed"));
    return;
  }
  
  Serial.print(F("requesting URL: "));
  Serial.print(twit_url1); Serial.print(twit_search); Serial.println(twit_url2);

  client.print(String("GET ") + twit_url1 + twit_search + twit_url2 + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "User-Agent: BuildFailureDetectorESP8266\r\n" +
               "Connection: close\r\n\r\n");

  Serial.println(F("request sent"));

  String dummy_str, dummy_str2, dummy_str3;
  String dummy_href_str="";
  int i, j=0;
  uint16_t Len;
  char c;

  Serial.println();

  TimeOut = millis();
  while (client.connected()) {
    if(millis()-TimeOut > 30000) break; //30秒経ってもレスポンスが無ければタイムアウト
    while (client.available()) {
      if(millis()-TimeOut > 30000) break; //30秒経ってもレスポンスが無ければタイムアウト
      if(dummy_str.indexOf(Final_tag) ==-1){
        for(i=0; i<70; i++){
          if(millis()-TimeOut > 30000) break; //30秒経ってもレスポンスが無ければタイムアウト
          c = client.read();
          if(c == '\n' || c >= 0xF0 || c == '>' || c < 0x20) break;
          dummy_str += String(c);
        }

        if(dummy_str.indexOf(Begin_tag) >= 0){
          Serial.println(F("--------------------"));
          dummy_str = client.readStringUntil('>');
          dummy_str3 = Paragraph;
          while(dummy_str.indexOf("/p") == -1){
            if(dummy_str.indexOf("href") >= 0){
              while(dummy_href_str.indexOf("</a") == -1){
                dummy_href_str = client.readStringUntil('>');
              }
              dummy_str=""; dummy_href_str="";
            }
            dummy_str2 = client.readStringUntil('<');
            if(dummy_str2.length()<2 && dummy_str2[0]<0x21){
              Serial.println(F("delete"));
            }else{
              dummy_str2.replace("&nbsp;"," ");
              dummy_str2.replace("&quot;","\"");
              dummy_str2.replace("&gt;","<");
              dummy_str2.replace("&lt;",">");
              dummy_str2.replace("&amp;","&");
              dummy_str2.replace("\0"," ");
              dummy_str2.replace(" "," "); //全角スペースを半角スペースにする。
              dummy_str2.replace("  "," "); //半角スペース×2を1つにする。
              dummy_str3 += dummy_str2;
              if(dummy_str2.length() > 450) dummy_str3 = dummy_str3.substring(0,449); //多すぎる文字はカット
              Serial.printf("UTF-8 code =%d bytes\n", dummy_str2.length()+1);
            }
            dummy_str2="";
            dummy_str = client.readStringUntil('>');
          }
          if(j<MaxTwitDisp){
            u8ts.UTF8_to_SJIS_str_cnv(UTF8SJIS, dummy_str3 + " ", sjis[j], &Len);
            sjis_length[j] = Len;
            Serial.printf("No.%d tweet Shift_JIS =%d bytes\n", j+1, Len);
          }
          j++;
          dummy_str3 = "";
        }
        if(dummy_str.indexOf(Final_tag) >= 0){
          Serial.println(F("Final tag </html>--------------"));
          while(client.available()){
            c = client.read();
            Serial.print(c);
          }
          dummy_str = ""; dummy_str2 = ""; dummy_href_str="";
          break;
        }
        dummy_str = ""; dummy_str2 = ""; dummy_href_str="";
      }else{
        Serial.println(F("Final </html>>>>>>>>>>>>>>>>>>>>>"));
        while(client.available()) c = client.read();
        dummy_str = ""; dummy_str2 = ""; dummy_href_str="";
        break;
      }
    }
  }
  Serial.println(F("%%%%%%%%%%%%%%%%%%%%%%"));
  if((j-1)>=0){
    *TwitCount = j;
  }else{
    *TwitCount = 0;
  }
  Serial.printf("Tweet Count=%d\r\n",j);
  delay(10);                
  client.stop();
  delay(10);
  client.flush();
}
//********************UTF-8文字列をパーセントエンコード*************************
String StrPerEncord(char* c_str){
  uint16_t i = 0;
  String str_ret = "";
  char c1[3], c2[3], c3[3];

  while(c_str[i] != '\0'){
    if(c_str[i]>=0xC2 && c_str[i]<=0xD1){//2バイト文字
      sprintf(c1, "%2x", c_str[i]);
      sprintf(c2, "%2x", c_str[i+1]);
      str_ret += "%" + String(c1) + "%" + String(c2);
      i = i+2;
    }else if(c_str[i]>=0xE2 && c_str[i]<=0xEF){
      sprintf(c1, "%2x", c_str[i]);
      sprintf(c2, "%2x", c_str[i+1]);
      sprintf(c3, "%2x", c_str[i+2]);
      str_ret += "%" + String(c1) + "%" + String(c2) + "%" + String(c3);
      i = i+3;
    }else{
      str_ret += String(c_str[i]);
      i++;
    }
  }
  return str_ret;
}

●16行目:
WiFiClientSecure.h がhttpsページ、つまりSSLページを取得するためのArduino Core for ESP8266 WiFi Chipライブラリです。

●17行目:
UTF8toSJIS は私の自作ライブラリで、UTF-8コードの文字列をShift_JISコードに変換するライブラリです。これには予めアップロードしてある変換テーブルファイルが必要です。

●18行目:
これも自作ライブラリです。ver1.53 で1ピクセルずつスクロールする関数を修正しました。

●19行目:
フリーの日本語漢字、東雲(しののめ)フォントを使うためのライブラリです。

●21-24行:
ライブラリのクラス名を指定します。

●26-30行:
SSD1351をSPI通信で制御するための、ESP-WROOM-02 ( ESP8266 ) のGPIOピン設定です。

●32-33行:
ここのxxxxのところをご自分のルーター、およびアクセスポイントのSSIDとパスワードに書き換えます。

●35-37行:
ここでSPIFFSアップロードしたファイル名を指定します。
必ずスラッシュは必要です。

●39行:
ツイッターのホスト名を指定

●40行:
セキュアーなSSL通信を行うためのポートは443ということです。普通のhttp通信ならば80ですね。確か・・・。

●41行:
ここでTwitter検索する文字列を入力します。日本語でも英語でもOKです。
ただ、お使いのArduino IDE スケッチの文字コードがUTF-8の場合です。恐らく、WindowsであればArduino IDE のスケッチはUTF-8になっていると思います。
日本語文字列の場合は、後のStrPerEncord関数でパーセントエンコードします。

●43行:
MaxTxt はShift_JISコード文字列の最大バイト数を指定しています。ツイッター投稿は最大140文字ですから、全て日本語だとするとShift_JISコードに変換すれば、倍の280バイト必要です。ちょっと余裕をみて300としました。これ以上にするとなぜか動作が不安定になるのでお勧めできませんのでご注意。
また、MaxTwitDisp は OLED ディスプレイで一度に表示できる最大列ですので8です。

●68行:
自作のOLED_SSD1351ライブラリで、SSD1351を初期化する関数です。SPI通信のESP-WROOM-02 ( ESP8266 ) のGPIOピンを指定します。

●74行:
初期画面で表示する文字列、UTF-8コード全角8文字をShift_JISコードに変換する自作ライブラリです。

●75行:
Shift_JISコード文字列を16×16ドットのフリーの日本語漢字、東雲フォントに変換する自作ライブラリです。文字列を一気にフォントのバイト列に変換します。これに関してはこちらのページも参照してみてください。

●76-77行:
これも自作ライブラリで、OLED SSD1351のディスプレイ1行分を一括表示するための関数です。ピクセル表示始め位置は、水平位置(column)がゼロ、つまり左端で、垂直位置(row)もゼロ、つまり上端としています。つまり、ディスプレイの一番上の列に文字列が表示されます。
色はGreenだけが最大値が63となります。これはSSD1351のデータシートにそのように指定してあります。今回のライブラリでは65k色指定となります。

●79-85行:
ここでOLEDに表示させるバイト列を初期化でゼロ、つまり黒色にしておかないとゴチャゴチャに表示されてしまいますので必ず必要です。

●88行:
今回作った202行~にある関数です。setup内で初回にTwitterへGETリクエストして、文字列を取得します。ついでにUTF-8文字列をShift_JISコードに変換しています。これの詳細は後述します。

●91-98行:
取得したShift_JIS文字列をシリアルモニターに表示させ、東雲フォントに変換して、各ツイートの全角8文字分で8列を青色で一気に表示します。

●124行:
ここで文字列のスクロール速度を調整してますが、現段階でSclSpeed = 0  が最速で、動画を見ていただけると分かると思いますが、もっと早くしたいくらいです。速くする方法が分かる方は教えていただきたいです。

●125-143行:
ここで、1行スクロールを終えたら、次の行の東雲フォントを抽出します。
dummy_font_buf にフォントデータを移して、そのデータがスクロールで1ピクセルずつ書き換えられています。

●145行:
これが今回新たに登場したライブラリ関数です。
この関数をループ内で一回実行すると半角8×16ドットのフォントデータが1ピクセル左に移動します。これが8回繰り返されると、半角1文字分左へスクロールします。この際、dummy_font_buf のデータが書き換えられています。

●147-160行:
1画面すべてスクロールし終えると、文字の色を変えていきます。

●161行:
ここでディスプレイ1列分のデータをSSD1351に一括出力します。

●166-200行:
3分毎にTwitterへGETリクエストを送ってツイートを取得し、ディスプレイに表示させてます。
ここで十分注意していただきたいのは、リクエストする間隔が短すぎると相手サーバーに負担がかかり、他の方々に迷惑をかけてしまう可能性がありますので気を付けてください。このプログラムの実行に関してはみなさんの自己責任ですのでご了承ください。

●203-330行:
TwitterへGETリクエストして、検索対象のツイートを取得する自作関数です。
host名の https://twitter.com という文字列に205-207行の文字列をブラウザのURL入力欄に入力すると、ツイッター検索のツイートを見ることが出来ます。
ただ、検索文字列はUTF-8コードでパーセントエンコードする必要があります。その関数は後述します。
211-240行まではサンプルスケッチそのまま使わせていただきました。
256-261行が注目です。ツイッターのページのソースコードを見ていただくと分かるのですが、途中に物凄いバイト数の1行の文字列があると思います。つまり、改行コードが出るまでに多量のバイト数がある1行です。
これが厄介で、HTMLタグをマイコンで解析するのに壁になるところです。
そこで、私は70バイトずつ読み込んでBegin_tagを見つけるという方法にしてみました。しかも、その中で改行コード’\n’が見つかればループを抜けるという方法です。
ただ、258行目の c = client.read(); でたまにフリーズするのです。この原因が全く分かりません。もしかしたら、ここで電圧が落ちてしまうときがあるのかと思ったのですが、しばらく放っておくと、その次の行からまたスタートするんですね。この原因が分かりません。解る方がいたらぜひ教えてください!!

263行から実際の欲しいツイートを抽出していきます。いまのところこの方法で抽出できています。
275-277行でAsciiコードの不要な制御コードなどを削除してます。
278-285行で文字化けするものを変換したりしてます。
293-297行で8ツイートまでを文字列変換します。後はツイッターホストからレスポンスで返ってきたデータをFinal_tagまで余さず受け取ることが大事です。ここで1バイトでも受け忘れると何かと不具合が起きるかもしれません。

●332-355行:
UTF-8日本語文字列をパーセントエンコードする関数です。
要するに、UTF-8文字コードは2バイト~3バイトなので、その書くバイトの間に ‘%’ という文字をいれるだけです。
ASCII の半角文字はそのまま出力します。

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

では、このスケッチをコンパイル書き込み実行してみてください。

うまくツイートをゲットできるとシリアルモニターでは下図の様に表示されます。
ここでは検索キーワードをbabymetalにしています。

ズラッと表示されたあとに、次のように日本語表示されると思います。
Shift_JISコードをシリアルモニターへ出力すると日本語表示されます。
ただしこれはWindowsの場合です。

このプログラムはまだフリーズすることがあるので、上手く動かない場合はリセットスイッチを押してみてください。いつか原因を掴んで改善していこうと思っていますので、現段階ではご容赦ください。

以上です。
半年前はツイートを趣味レベルで表示できるなんて夢のまた夢でしたが、今回は未完成ながらも何とか達成できました。 今後はもっと精度を上げていければなぁと思ってます。

ではまた・・・。

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

スイッチサイエンス ESPr Developer 32 Type-C SSCI-063647
スイッチサイエンス
¥2,420(2024/12/26 11:02時点)
ZEROPLUS ロジックアナライザ LAP-C(16032)
ZEROPLUS
¥28,006(2024/12/26 17:56時点)
Excelでわかるディープラーニング超入門
技術評論社
¥2,068(2024/12/26 09:03時点)

コメント

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