九州・福岡・東京ときどきIoT

21年間のはてなダイアリー&アメブロからの避難所

多機能・高信頼性 RSSニュースリーダー プログラム仕様書

プログラム仕様書

多機能・高信頼性 RSSニュースリーダー

項目

内容

ドキュメントバージョン

2.0 (最終完成版)

作成日

2025年6月10日

作成者

 不許複製

技術協力

 不許複製                     

プログラム仕様書 - 項目リスト

1. 概要

2. 機能仕様

  2.1. 起動シーケンス

  2.2. 表示レイアウト

  2.3. ステータスバー仕様

  2.4. コンテンツ表示仕様

  2.5. アニメーション仕様

  2.6. データ取得・巡回・回復仕様

3. 主要アルゴリズム解説 

 3.1. 2キャンバス描画方式

  3.2. 状態管理によるアプリケーション制御

  3.3. 堅牢化設計(回復処理)

4. プログラムリスト

5. 巻末付録:主要変数リスト (VALLIST)

 

1. 概要

本プログラムは、ESP32マイクロコントローラとST7735カラーTFT液晶ディスプレイを使用し、インターネット経由でRSSフィードを取得してニュースタイトルを表示する、自律型のニュースリーダーアプリケーションである。

複数のRSSソース(XML形式、RDF形式を含む)を巡回し、取得したニュースを視覚的に魅力のあるインターフェースで表示する。描画には2キャンバス方式を採用し、ちらつきや表示の重なりのない滑らかなアニメーションを実現。さらに、起動失敗時の自動再起動や、WiFi切断からの自動回復機能を備え、安定した長期稼働を目指した高信頼性設計となっている。

2. 機能仕様

2.1. 起動シーケンス

  • 電源投入後、アプリケーションは起動シーケンスに入る。
  • TFT画面とシリアルモニタの両方に、以下の進捗状況をリアルタイムで表示する。
    1. Booting RSS Reader... (空きヒープ量表示)
    2. Connecting to WiFi... (接続中は . が追記される)
    3. Syncing Time (NTP)...
    4. Fetching initial RSS... (HTTPステータスコード表示)
    5. Loading...
  • WiFi接続や初回RSS取得に失敗した場合は、エラーメッセージを画面に表示後、5秒で自動的に再起動し、復帰を試みる。

2.2. 表示レイアウト

画面は、上下2つの領域に明確に分割されている。

  • ステータスバー領域 (上部12ピクセル): 常に画面上部に固定表示され、コンテンツのスクロールによる影響を受けない。
  • コンテンツ領域 (下部116ピクセル): ニュースの出典とタイトルが表示され、内容が長い場合は縦横にスクロールする。

2.3. ステータスバー仕様

  • 背景色:
  • 文字色:
  • 左側: RSSフィードを最後に取得した時刻を YYYY/MM/DD hh:mm:ss の形式で表示。時刻は起動時にNTPサーバーと同期する。
  • 右側: 現在表示中のニュースが、そのフィード内の何番目かを示すカウントを (現在のトピック番号) / (総トピック数) の形式で表示。

 

2.4. コンテンツ表示仕様

  • 配色:
    • 背景: 深緑
    • 出典元テキスト: 白
    • ニュースタイトル: 黄
  • 表示順: 1つのトピックにつき、まず出典元、改行してニュースタイトルが表示される。
  • フォント: 表示には、より多くの漢字を収録した u8g2_font_unifont_t_japanese3 を使用し、文字化けを最小限に抑える。

2.5. アニメーション仕様

  • 縦スクロール: トピックの行数が画面に収まりきらない場合、ピクセル単位で滑らかに上方へ自動スクロールする。スクロール範囲はコンテンツ領域の高さに合わせて正確に計算され、トピックの最後まで表示される。
  • 横スクロール: 一つのトピックの表示が完了すると、現在の画面(縦スクロール後の最終表示状態)が左方向へスクロールアウトする。右から現れるのはブランク(背景色)画面であり、アニメーション完了後に次のトピックが表示される。

2.6. データ取得・巡回・回復仕様

  • RSS:
    • あらかじめ定義された複数のRSSフィードXML, RDF形式に対応)のURLリストを持つ。
    • 一つのフィードの全トピックを表示し終えると、リストの次のフィードを取得しにいく。
    • リストの最後のフィードを終えると、自動的に先頭のフィードに戻り、表示を継続する。
    • 特定のフィードの取得や解析に失敗した場合、プログラムは停止せず、そのフィードを自動的にスキップして次のフィードの取得を試みる。
  • WiFi:
    • 起動時だけでなく、メインループ実行中も常に接続状態を監視。
    • 万が一WiFi接続が切断された場合、自動で再接続処理を開始し、自律的な復帰を試みる。







3. 主要アルゴリズム解説

3.1. 2キャンバス描画方式

本アプリケーションの滑らかで安定した描画を実現する、最も重要な技術。

  • 目的: 画面のちらつきや、ステータスバーとコンテンツの表示が重なる問題を物理的に防ぐ。
  • 仕組み:
    1. メモリ上に、画面には見えない2つの描画領域(キャンバス)を用意する。
    2. ステータスバーに関する描画はすべて statusBarCanvas に対してのみ行う。
    3. ニュース本文の描画やスクロールはすべて contentCanvas に対してのみ行う。座標計算もこのキャンバス内(0,0)を基準とするため、他領域への影響を完全に排除できる。
    4. 最後に、完成した2枚のキャンバスを、物理ディスプレイの正しい位置(y=0y=12)に一括で転送・合成(compositeScreen)することで、1フレームの描画が完了する。

3.2. 状態管理によるアプリケーション制御

enum class DisplayState を用いた有限ステートマシンにより、アプリケーションの動作を管理する。

  • 状態:
    • START_TOPIC: トピック表示開始(静止)
    • V_SCROLLING: 縦スクロール中
    • END_TOPIC: 縦スクロール終了(静止)
    • H_SCROLLING: 横スクロールによる場面転換
    • ERROR: 回復不能なエラーが発生し、停止した状態
  • 遷移: loop()関数内で、経過時間や処理の完了に応じて、これらの状態を順番に遷移させることで、一連の表示シーケンスを実現している。

3.3. 堅牢化設計(回復処理)

  • 起動失敗リカバリ: setup()関数内でWiFi接続や初回RSS取得に失敗した場合、ESP.restart()を呼び出し、自動的にウォームスタートを行うことで、一時的な問題からの自己回復を試みる。
  • 運用中WiFi切断リカバリ: loop()関数の冒頭で常にWiFi.status()を監視。切断を検知した場合、reconnectWiFi()関数を呼び出して再接続を試みる。
  • RSS取得失敗リカバリ: fetchRSS()関数は取得・解析の成否をbool値で返す。loop()内でこれを受け取り、失敗(false)した場合は、エラー表示などは行わず、単純に次のフィードの取得処理へ移行する(スキップ処理)。

4. プログラムリスト

(ここに、最終版のプログラムコード全文を添付)




割愛します。



















  1. 巻末付録:主要変数リスト (VALLIST)

変数名

役割・概要

主な更新箇所

currentState

DisplayState (enum)

アプリの現在の動作状態を管理する最も重要な変数。<br>「表示開始」「縦スクロール中」「表示終了」「横スクロール中」「エラー」の状態を持つ。

loop()関数内のswitch文で、時間経過や処理完了に応じて更新。

currentRSSIndex

int

RSS_URLS配列の何番目を読んでいるかを示すインデックス(0~5)。次にどのフィードを取得するかを決定する。

loop()関数内で、一つのフィードの全トピック表示が完了した後に+1される。リストの末尾に達すると0に戻る。

currentTopicIndex

int

allTopicsベクターの何番目を読んでいるかを示すインデックス。現在表示中のニュースが、そのフィード内で何番目かを管理する。

loop()関数内で、横スクロールが完了した後に+1される。新しいフィードが取得されると0にリセット。

allTopics

std::vector<Topic>

fetchRSS()で取得した一つのフィード分の全トピック(出典とタイトル)を格納する動的配列。

fetchRSS()関数が呼び出されるたびに、一度クリアされてから新しい内容が格納される。

currentTopicLines

std::vector<String>

allTopicsの中から現在表示中の単一トピックを、画面幅で折り返して行分割した文字列を格納する動的配列。

prepareTopic()関数内で、表示するトピックが切り替わるたびにクリアされ、新しい内容が格納される。

sourceLineCount

int

currentTopicLinesのうち、出典テキストが何行を占めるかを記録する。出典(白)とタイトル(黄)を正しく色分けするために使用。

prepareTopic()関数内で、トピックの準備時に計算される。

verticalScrollOffset

int

コンテンツ領域内での、ピクセル単位の縦スクロール量を保持する。この値を変えることで、滑らかなスクロールを実現している。

loop()関数内のV_SCROLLING状態で+1ずつ加算される。prepareTopic()で新しいトピックが表示される際に0にリセット。

lastActionTime

unsigned long

millis()によるタイムスタンプ。状態遷移のタイミング(「3秒待つ」「0.05秒ごとにスクロールする」など)を管理する。

loop()関数内で、各状態のアクションが実行されるたびに更新される。

lastFetchTimeString

char[20]

ステータスバーに表示するための、フォーマット済みの日時文字列(例: 2025/06/10 17:23:20)。

updateFetchTime()関数内で、NTP同期後やRSS取得成功時に更新される。

statusBarCanvas

GFXcanvas16

画面上部のステータスバー(160x12)専用の描画領域(見えない画用紙)。

drawStatusBar()関数によって内容が描画される。

contentCanvas

GFXcanvas16

下部のコンテンツ領域(160x116)専用の描画領域。スクロールするニュース本文は全てここに描画される。

drawContent()関数によって内容が描画される。