プログラム仕様書
多機能・高信頼性 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画面とシリアルモニタの両方に、以下の進捗状況をリアルタイムで表示する。
- Booting RSS Reader... (空きヒープ量表示)
- Connecting to WiFi... (接続中は . が追記される)
- Syncing Time (NTP)...
- Fetching initial RSS... (HTTPステータスコード表示)
- 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キャンバス描画方式
本アプリケーションの滑らかで安定した描画を実現する、最も重要な技術。
- 目的: 画面のちらつきや、ステータスバーとコンテンツの表示が重なる問題を物理的に防ぐ。
- 仕組み:
- メモリ上に、画面には見えない2つの描画領域(キャンバス)を用意する。
- ステータスバーに関する描画はすべて statusBarCanvas に対してのみ行う。
- ニュース本文の描画やスクロールはすべて contentCanvas に対してのみ行う。座標計算もこのキャンバス内(0,0)を基準とするため、他領域への影響を完全に排除できる。
- 最後に、完成した2枚のキャンバスを、物理ディスプレイの正しい位置(y=0 と y=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. プログラムリスト
(ここに、最終版のプログラムコード全文を添付)
割愛します。
- 巻末付録:主要変数リスト (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()関数によって内容が描画される。 |