フューチャー技術ブログ

お家で電子工作入門 ~上空のフライト情報を可視化する🛫~

はじめに

本記事は春の入門祭り2日目の記事となります。
今日はM5Stackを使ったお家電子工作の沼へ誘いたいと思います。

過去にも電子工作連載があり、Futureでは活発にお家電子工作をやっております。

https://future-architect.github.io/articles/20220404a/

何を作るか考える

お家電子工作はワクワクが原動力なので、何かワクワクするものを作りたいなーと考えてみました。

うーんと考えてみたところ、この3年間コロナもあり海外に全然行ってないなーと。

海外に行くときのワクワクはまず空港に到着してフライト情報を眺めることから始まります。

じゃあ、自分の住んでいる周辺を飛ぶ飛行機の情報を表示することで、その飛行機に思いを馳せてワクワクするんじゃないかと考えました。

必要なもの

M5Stackはいいゾ

とりあえずお家で電子工作やIoTをやってみたい方はぜひ1台持っておくとよいです。ほぼ何でもできます。

学生時代にM5Stack拡張して、赤外線サバゲー作ってたりもしました。

https://www.youtube.com/watch?v=deW3GmdMe_M

環境構築

VSCodeは公式ページからインストールして下さい。
VSCodeの拡張機能であるPlatformIO IDEを使って開発を行います。
PlatformIO IDEの導入はこちらの記事を参考にして下さい。

プロジェクトの作成

拡張機能のインストールが終わると、Welcome画面が出てきます。
「New Project」からプロジェクトを作成しましょう。

  • Name: Future_Tech_Blog(なんでもよいです)。
  • Board: M5Stack Core ESP32
  • Framework: Arduino

以下のようなディレクトリ構成でプロジェクトが作成されます。

ライブラリのインストール

今回は以下のライブラリを使用します。

  • M5Stack.h
    • M5Stackの各種機能を使うためのライブラリ
  • Wi-Fi.h
    • Wi-Fiに接続するためのライブラリ
  • HTTPClient.h
    • GETリクエストを送るためのライブラリ
  • ArduinoJson.h
    • JSONを扱うためのライブラリ
  • time.h
    • 時刻を扱ったり、変換したりするためのライブラリ

PlatformIOでのライブラリインストールは以下の手順で行っていきます。

PlatformIO Home画面から「Libraries」を選択します。

M5Stack.hを例にライブラリを検索します。

該当のライブラリをクリックします。

「Add to Project」からプロジェクトへ追加します。

「Select a project」から作成したプロジェクトを選択し、「Add」を押すことで追加できます。

これをあとArduinoJsonとTimeに対して行うことで準備完了です。
HTTPClientやWi-Fiに対しては不要です。

Flightrader24を理解する

Flightrader24は世界中のフライト情報を取得できます。

iOSやAndroidのアプリもあり、触ったことがある人も居るのではないでしょうか?

Flightrader24ではREST APIも公開していて、以下のURLにGETリクエストするとJSONでデータを取得できます。

http://data-live.flightradar24.com/zones/fcgi/feed.js?adsb=1&mlat=1&faa=1&flarm=1&estimated=1&air=1&gnd=1&vehicles=1&gliders=1&array=1

各クエリパラメータの説明は以下に詳しく書いてあります。
JSON - Flightradar24 から飛行中の航空機情報を取得!

ここでbounds=というクエリパラメータを追加し、緯度(北)・緯度(南)・経度(西)・経度(東)の順で値を入れていくとフライト情報を取得するエリアを指定できます。

今回は大崎がある品川区の端から端を指定してみます。

どうやって緯度・経度を取得するかって? それはChat-GPTにお任せです。

こういう調べても出てきそうにない情報は初手Chat-GPTがおススメです。
緯度・経度が得られたのでクエリパラメータを指定したURLが以下になります。

http://data-live.flightradar24.com/zones/fcgi/feed.js?bounds=35.63,35.59,139.71,139.76&adsb=1&mlat=1&faa=1&flarm=1&estimated=1&air=1&gnd=1&vehicles=1&gliders=1&array=1

これでGETしてみたところ、取得できませんでした。
さすがに範囲が狭すぎたようなので小数点第二位を四捨五入して取得したところ、以下のようなフライト情報が取得できました。

['2fe70675', '4D23DB', 35.5631, 139.7589, 329, 0, 1, '', 'T-RJTT172', 'GL7T', '9H-VIL', 1681552816, 'XSP', 'HND', 'VJT735', 1, 0, 'VJT735', 0]

各項目の意味は先ほどのリンクを参考にしてください。
JSON - Flightradar24 から飛行中の航空機情報を取得!

とりあえず、10: 便名、11: 時刻、12: 出発空港, 13: 到着空港がわかれば楽しめそうです。

M5Stack側のコードを作成

M5Stackはsetup()loop()の2つの大きな関数による構造となっております。
setup()は最初の1度しか呼ばれず、残りはloop()が名前の通り永遠に呼ばれるようになっています。

コード全体はこちらのGitHubに置いてあります。

https://github.com/bigface0202/flightM5rader

setup側

setup側は起動後の1度しか呼ばれないため、主に接続を確立したり、画面の初期設定を行うなどの処理を記述します。

M5Stackのディスプレイ設定

M5Stackのディスプレイには文字や画像を表示できます。
その初期設定を以下のように記述します。

// M5Stackの初期化
M5.begin();
// フォントサイズ
M5.Lcd.setTextFont(4);
// フォントカラー
M5.Lcd.setTextColor(WHITE);
// 文字の初期位置
M5.Lcd.setCursor(0, 0);

Wi-Fiへ接続

今回はHTTPリクエストを投げる必要があるため、Wi-Fiへの接続は必須となります。
WIFI_SSIDWIFI_PASSWORDを自宅のWi-Fiの情報に書き換えることで接続できるようになります。
また、5GHz帯は接続不可能なため2.4GHz帯のWi-Fiを選んで下さい。

// WiFiに接続
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
int _cursorX = 0;
M5.Lcd.print("Connecting to Wi-Fi");
// 接続を試みている状態を画面に表示
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
M5.Lcd.setCursor(0 + 5 * _cursorX, 30);
M5.Lcd.print(".");
delay(300);
_cursorX++;
if (_cursorX > 320) {
_cursorX = 0;
}
}

loop側

loop側は主に処理をさせたい内容を記述していきます。
今回の場合だと、フライト情報の取得とその情報の変換・表示になります。

リクエストを投げる

GETリクエストは以下のように投げることができます。
毎回、取得できるとは限らないのでHTTP_CODE_OK以外の時はエラーコードを表示するにようにしています。
また、GETリクエストを送る際はdelayを最後に挟むようにしてください。
delayを入れないとマシンガンリクエストを送ることになり、APIサーバーに対して負荷をかけてしまうため大変よろしくないです。

HTTPClient http;
String apiAddress = "http://data-live.flightradar24.com/zones/fcgi/feed.js?bounds=35.6,35.5,139.7,139.8&adsb=1&mlat=1&faa=1&flarm=1&estimated=1&air=1&gnd=1&vehicles=1&gliders=1&array=1";

void loop() {
String payload;
http.begin(apiAddress);
int httpCode = http.GET();

if (httpCode > 0) {
if (httpCode == HTTP_CODE_OK) {
// 以下、取得したデータの処理
// ...
} else {
M5.Lcd.setCursor(0, 0);
M5.Lcd.print("HTTP GET ERROR: ");
M5.Lcd.println(httpCode);
delay(5000);
}
// delayを入れ忘れるとマシンガンリクエストになるので、忘れずに
delay(5000);
}

取得したJSONの処理と表示

Flightrader24にリクエストを送って取得した情報を表示していきます。
基本的に取得した配列に対して、ループで3秒ごとに表示していく処理になります。
1点だけ注意したいのが、リクエストを投げて得られる時刻がUNIX時間なので人間が読める時間に変換する必要があり、そちらの関数unix2datetimeは後述します。

// JSON取得用の変数
DynamicJsonDocument doc(4096);
// リクエストで取得した情報を格納
payload = http.getString();
// String -> JSON
deserializeJson(doc, payload);
// 配列の大きさを取得
int len = doc["aircraft"].size();
// 配列の数だけフライト情報を表示
for (int i = 0; i < len; i++) {
String flightName = doc["aircraft"][i][10];
time_t unixTimeUTC = doc["aircraft"][i][11];
String departure = doc["aircraft"][i][12];
String arrival = doc["aircraft"][i][13];

// Unix timeから日本時間へ変換
String dateTimeString = unix2datetime(unixTimeUTC);
// 表示
M5.Lcd.setCursor(0, 0);
M5.Lcd.print("Flight Name: ");
M5.Lcd.println(flightName);
M5.Lcd.print("Time: ");
M5.Lcd.println(dateTimeString);
M5.Lcd.print("Departure: ");
M5.Lcd.println(departure);
M5.Lcd.print("arrival: ");
M5.Lcd.println(arrival);
// 3秒待つ
delay(3000);
// 画面初期化
M5.Lcd.fillScreen(BLACK);

UNIX時間を変換する

Chat-GPTマジ便利。
要所要所で詰まったらChat-GPT先生にお任せしたほうが早いです。

unix2datetime
String unix2datetime(time_t unixTime) {
time_t unixTimeJTC = unixTime + 32400;
struct tm *tmTime = localtime(&unixTimeJTC);
char dateTimeString[20];
strftime(dateTimeString, sizeof(dateTimeString), "%Y-%m-%d %H:%M:%S", tmTime);

return dateTimeString;
}

画像を表示する(おまけ)

ここからは機能的にはあまり関係ないのでおまけになりますが、こうやって遊びを入れることで自分のプロダクトに愛着が沸きます。
現在の状態だと画面にフライト情報の文字だけが表示されて味気ないので、フライト情報のAPIをGETする際に飛行機の画像を表示します。

画像はこちらのフリー素材をサイズ変更(幅160px)してダウンロードし、SDカードにフォルダ(フォルダ名:img)を作成して取り込んで下さい。
取り込み終わったSDカードはM5Stackに挿しましょう。

https://jitanda.com/2014/02/07/j413_6/

また、LavyanGFXをライブラリインストールの手順でやったようにインストールして下さい。

コードでは画像をsprite.pushRotateZoom()で徐々に拡大させることで、近づいてきているようなエフェクトを作ってみます。

#define LGFX_AUTODETECT

#include <LovyanGFX.hpp>
#include <LGFX_AUTODETECT.hpp>

static LGFX lcd;
static LGFX_Sprite sprite(&lcd);

// 画像サイズが違うかもなので、ここはよしなに変えて下さい
int width = 160;
int height = 120;

void setup()
{
// 初期化処理
lcd.init();
lcd.clear(TFT_BLACK);
SD.begin(TFCARD_CS_PIN, SPI, 20000000);

// 画像の読み込み
sprite.createSprite(width, height);
sprite.drawPngFile(SD, "/img/airplane.png", 0, 0);
// ...
}

void loop()
{
// 画像を徐々にズーム
for (int i = 0; i < 10; i ++) {
sprite.pushRotateZoom(width, height, 0, i, i);
delay(100);
}
//...
}

できあがったもの

m5stack_airplane3.gif

まとめ

こうやってハードウェア込みで自分がワクワクするものを開発できるのがお家電子工作の良いところですね。GPSモジュールなんかもあるので、位置情報のあたりも自動化するなど色々工夫もできそうです。

ぜひ皆さんもLet’s enjoy お家電子工作してください。

明日は井上さんで初めてのセキュリティ情報収集(mjckeck4)です。

アイキャッチは時短だ飛行機38を使わせていただきました。