Twitterで星空botを運用しています

毎日の星空の様子や天体の位置などをTwitterでツイートするbotを作って2年前から運用しています。

@hoshizora_today

開発した当時にこのブログで紹介するのを忘れていたのでいつか書こうと思っていたのですが、Twitterの経営方針が変わって今後のTwitterbot運用がどうなるのか不透明で、botがいつ止まってしまうかもわからないので、このタイミングで思い出としてbotの設計を記憶の範囲で書いておきます。

このbotは、天体の位置を計算できるものはツイートを自動生成し、ツイート頻度が低く計算のハードルが高い内容は事前に手動でツイートを作成しています。

以前からこういうのを作りたいと思いながら、計算するプログラムをどう書いていいのかわからなくて挫折していました。しかし、約2年前に改めて調べてみたところ、勢いで計算できちゃったので、運用始めました。

ツイート内容の計算方法

太陽や月、惑星の位置は、NASAJPL(Jet Propulsion Laboratory)が公開しているDE430というデータから計算しています。このデータは軌道要素ではなく、32日間の期間ごとのチェビシェフ多項式の係数が含まれており、係数から惑星の位置を計算できるようになっています。軌道要素のずれである摂動を考慮済みの位置を直接計算できます。

チェビシェフ多項式については以前に以下の記事を書きました。

チェビシェフ多項式(Chebyshev polynomials)でフィットさせた係数から値を復元 - suzuki-navi’s blog

地球からの惑星や月の相対位置を計算するにはまず地球の位置を計算する必要があります。地球の位置を直接計算するデータはDE430にはありません。かわりに、地球・月系の重心位置、および地球から見た月の位置を計算するためのデータがDE430にあります。この2つから地球の位置を計算することになります。

恒星時は時間の1次関数です。特定の時間における惑星や星座の方位角や高度は、恒星時と東京の経緯度から計算しています。地心視差は考慮していません。本当は月に関しては地心視差を考慮したほうがいいかもしれません。

星座に関するツイートは、あらかじめ原稿を用意していて、恒星時からツイートするタイミングだけを計算しています。

構成

ツイートテキスト生成と自動ツイートの2つの構成です。

ツイートテキスト生成

ツイートテキストを生成するローカルで動かすプログラムです。ツイートテキストとツイート時間のペアの一覧をこのプログラムで生成して、AWSのS3にアップロードします。単一のテキストファイルを生成しています。

プログラムの構成は最初に作ったときから半年ほどかけて少しずつ変わりました。

Ruby

Ruby + Scala

Ruby + Scala + Node.js

Scala + Node.js

Scala

一番最初はRubyだけで実装していました。なぜRubyなのかというと以下の方のgemを利用したかったためです。

Ruby - JPL 天文暦 gem の作成! - mk-mode BLOG

しかし、ツイート内容の柔軟な生成がRubyでは辛かったのと、計算速度が遅かったため、途中で一部をScalaにしました。さらに、自動生成と手動生成をマージするところだけNode.jsで書きました。マージ処理の言語はなんでもよかったのですが、後述の通りPythonもすでに併用していたので、せっかくならばとバラバラな言語で書いてみました。

その後、計算速度改善のためRubyのコードは全部Scalaに置き換わりました。その後、ロジックの柔軟な対応のためにNode.jsでの実装もScalaに置き換えました。

ソースコードは以下にあります。リファクタリングをしようとして中途半端になっており、非常に汚いコードです。手動で作成したツイート内容はテキストファイルで書いてあります。

https://github.com/suzuki-navi/hoshizora_today/tree/main/calc

自動ツイート

AWS Lambdaで動くプログラムです。Twitter APIにアクセスしてツイートします。Pythonで書きました。

EventBridgeで5分に一度Lambdaを起動します。S3からデータを読み取って、その時間帯にツイートすべきテキストがあればツイートします。

Pythonソースコードは以下にあります。

https://github.com/suzuki-navi/hoshizora_today/blob/main/tweet/tweet.py

Twitter APIにアクセスするのはtwitterというずばりな名前のパッケージを使っています。

twitter · PyPI

ツイートテキストに出てくる用語集

  • 月相
    • 新月から次の新月までを0から28として、月の満ち欠けの状態を表した数値です。7が上弦の月、14が満月、21が下弦の月を表します。平均すると24時間で0.95ずつ進みますが、月の軌道が楕円で速度が一定でないため、月相の進み方も一定ではありません。星空botでは地球から見た太陽と月の黄経差で計算しています。地心視差は考慮していません。星空botでは0から28で表現していますが、0から360で表現することもあるようです。
  • 南中
    • 北天の天体であれば天の北極から、観測地点の天頂を通って、天の南極に達する直線を天体が通過することです。日本からであれば、惑星や南天の星ならば真南を通過することです。北天の星なら北極星の上です。
  • 黄道十二星座
  • 二十四節気
    • 天球上の太陽の通り道を24等分した点を太陽が通過する瞬間です。24個に名前が付いています。春分夏至秋分冬至はよく知られている二十四節気ですが、それ以外にも20個あります。
    • 地球よりも外側を回る惑星(火星、木星土星など)が、地球から見て太陽と反対の方向に来た瞬間です。太陽と反対なので、夜に見えやすい位置です。地球との距離も衝の前後に近くなります。
    • 地球から見て太陽と同じ方向に惑星が来た瞬間です。この前後は地球からその惑星を観測ることができません。地球よりも外側を回る惑星(火星、木星土星など)は、地球から見て太陽よりも向こう側になります。地球よりも内側を回る惑星(水星、金星)は、太陽よりも向こう側に来る外合と、太陽よりも手前に来る内合の2種類あります。

以下のページにも説明を書いています。

hoshizora_today

開発当時のブログ記事

このbotを開発するときに書いた関連するブログ記事は以下があります。

これを見るといろいろな言語で試行錯誤していたようです。当初はRubyで全部書こうとしていたのでAWS LambdaでRubyを動かす方法を調べていたのですが、途中で言語は適材適所と考え直し、AWS LambdaからTwitter APIにアクセスする部分はPythonで書くことにしたのだと思われます。