某庁の現業室にある時計を「再び」再現してみた
2025.12.06 · 3933 words · 8 minute readこの記事ではアフィリエイト広告を利用しています
目次
この記事は 防災アプリ開発 Advent Calendar 2025 の6日目の記事です。
某庁のオペレーションルーム(現業室)に設置されている時計を今度はウルトラワイドAndroidサイネージ端末で再現してみたお話です。
今年5月に8.8インチの横長モニター(通称、ツイ廃液晶)とRaspberry Piを使って、某庁のオペレーションルーム(現業室)にある時計のミニチュア再現版である opr-clock を作成しました。

Raspberry Pi Zero 2 Wと8.8インチ横長モニターで作ったopr-clock
卓上に置くには最適なサイズ感であるものの、もう少し大きいと壁掛け時計としても使えるのに…と思っていたところに、29インチのウルトラワイドディスプレイにAndroid 7.1を搭載したサイネージ端末の中古品が3,980円で特価販売されていたので、これを使って より実寸に近いサイズの現業室時計を作ろう というお話です。
1. サイネージ端末の仕様

LD290EJS-FPN1の表(画像下)と裏(画像上)。左下はサイズ比較用の Pixel 10 Pro
今回使用するサイネージ端末はLG Displayが展開しているin-TOUCH Stretch Displayシリーズの29インチモデル「LD290EJS-FPN1」で、日本国内ではPCパーツなどの代理店として有名なアスクが取り扱っていたようです。(現在は販売終了)
以下、主要な仕様を抜粋します。(販売終了につき製品ページが消える可能性があるためバックアップも兼ねて…)
| ディスプレイ | パネル | 29インチ TFT-LCD(IPS) | |
| 解像度 | 1920×540(32:9) | ||
| リフレッシュレート | 60Hz | ||
| 輝度 | 500nit | ||
| 表示領域 | 698.4(H)×210.03(V) mm | ||
| ベゼル幅 | 7.2(LR)/7.7(U)/9.6(D) mm | ||
| 外形寸法 | 713(H)×215.8(V) mm | ||
| 表面処理 | AG, 4H | ||
| タッチ | レポートレート | 60Hz | |
| マルチタッチ | 10ポイント未満 | ||
| 遅延時間 | 35ms以下 | ||
| 精度 | 3.5mm以下 | ||
| 最低感知サイズ | 6φ | ||
| I/O | Micro USB 2.0: Host×1, OTG×1 | ||
| CPU | ARM Coretex-A17, Quad-core, 1.6GHz | ||
| OS | Android 7.1 | ||
| メモリー | 1GB DDR3 | ||
| RAM領域 | 8GB eMMC, 空き領域約4.4GB | ||
| ワイヤレス | WiFi2.4: 802.11 b/g/n 2.4GHz, BT4.0 | ||
| 消費電力 | 30W未満 | ||
| 電源 | 12V3A, Type-C | ||
| 重量 | 2.80 Kg | ||
スペック上で気になるところをいくつか挙げてみます。
解像度は1920x540の32:9で、これは1920x1080を横半分に切ったような形。最近のウルトラワイドといえば3840x1080などの1920x1080が2枚並んだような解像度が多いので、解像度的には一昔前といったところでしょうか。
ディスプレイの表面がAG(アンチグレア)で硬度4Hなのは嬉しいですね。実際に触った感触としても硬いので保護フィルムなども必要なさそうです。
I/Oは Micro USB 2.0: Host×1, OTG×1 とありますが、実際にはこれに加えてMicroHDMI端子が1つ付いています。しかしながら入力としては使えないようなので出力用でしょうか。(HDMI周りは動作未確認)
CPUはCoretex-A17なので32bitです。昨今は64bitのCPUが主流なのでこれもちょっと古いですね。1.6GHzのクアッドコアとなっていますが、メモリーが1GBなので重いアプリを動かすのは厳しそうです。
内蔵ストレージは8GBのeMMCで空きは半分くらいなので、何らかの写真や動画などのコンテンツを再生したい場合はUSBフラッシュメモリーに入れてOTGケーブルで接続してあげる方が良さそうです。
無線周りはIEEE 802.11 b/g/nなのでWi-Fi4相当、ただし2.4GHzのみで5GHzは使えません。一応Bluetoothも4.0ですが使えるようです。4.0ということはBLEが使えそうですね。
OSはAndroid 7.1.2(APIレベル25)です。リリースが2017年4月頃なので約9年前のOSということになります。この辺りのバージョンのAndroidは多種多様なデバイスに搭載されていて技術的に枯れているのでアプリを作りやすいです。

モバイルバッテリーで動作中のLD290EJS-FPN1。12.1V/1.4A=約17Wで動作中。
消費電力は30W未満となっていますが、計測したところ画面の明るさ次第で10W台〜20W台と大きく変動します。電源として12V3A(=36W)の記載がありますが、昨今のUSB-PD出力対応USB充電器やモバイルバッテリーだと30W程度まで対応しているものが多いので、12Vのトリガーケーブル と 変換ケーブルを一緒に使うことで専用ACアダプターは無くても動きます。
ちなみに、ACアダプター付きの場合についてくるのは「FSP036-DHUA2」という型番のACアダプターらしい。出力は12V3AでアスクがPSE認証を取得している模様。
私が購入したものはACアダプターが付いていなかったので、12V3A で DC5521(外径5.5mm/内径2.1mm)プラグ のACアダプターと DC5521メスからUSB-Cオス への変換ケーブルを別途購入して使っています。
2. アプリの設計と実装
仕様が分かったところで、早速アプリを作っていきます。Chromeを搭載しているのでブラウザで動くアプリとして作っても良いかもと思いましたが、既にOSのアップデートなどが終わっていることや初期状態でGoogle Play Storeが入っておらずChromeのアップデートが面倒なため、今回はKotlinでネイティブアプリとして作りました。
作ったアプリのコードは opr-clock-android として公開しています。

アプリの処理の流れとしてはザックリと以下のようになります。起動後は2〜5の繰り返しです。
1. アプリ起動時の初期化 onCreate
- カスタム描画ビュー
SignageClockViewを全面に設定 - フルスクリーン設定
window.decorView.systemUiVisibility - 画面の常時点灯設定
FLAG_KEEP_SCREEN_ON - NTPサーバとの初回同期
trueTime.syncOnceAsync()
2. 正確な現在時刻を取得する SntpClient TrueTimeProvider
- UDPでNTPサーバにパケットを送信し、応答のタイムスタンプをパース
- NTP時刻(1900年基準)を UNIX時刻(1970年基準)に変換
- NTPサーバからの時刻(UNIX時刻)を
lastNtpTimeMillisに保存 - 端末が起動してから経過した時刻
elapsedRealtime()を問い合わせ時requestTimeと応答時responseTimeに保存 responseTimeからrequestTimeを引いてRTTroundTripを求め、半分に割って片道の時間ntpTimeReferenceMillisを保存lastNtpTimeMillis+ (elapsedRealtime()-lastNtpReferenceElapsed)で正確な現在時刻が求まる
3. 1秒ごとの画面更新タイマーを動かす updateRunnable
updateTime()で現在時刻を描画trueTime.nowJst()で日本標準時のCalendarを生成trueTime.nowUtc()でグリニッジ標準時のCalendarを生成SignageClockView.setTime(jst, utc)に渡すinvalidate()メソッドでSignageClockViewを再描画
- 現在時刻を取得して
val now = trueTime.nowMillis() - 次の秒までの差分を計算して
val delay = 1000 - (now % 1000) delay時間後に再度updateRunnableを実行させるupdateHandler.postDelayed(this, delay)
4. 日付と時刻を整形して描画する SignageClockView
1920x540の中に座標指定でちまちま描いていく(RasPi版 opr-clock と同じような感じ)
5. 10分毎に時刻を再同期する syncRunnable
- 10分毎に
trueTime.syncOnceAsync()を呼び出すsyncHandler.postDelayed(this, 10 * 60 * 1000L)
RasPi版 opr-clock では timedatectl でNTP設定を行うことで時刻同期していましたが、このアプリでは端末のシステム時計を使用(信用)せず、NTPサーバと直接同期して時刻を表示するようにしています。
当初はシステム時計を使用して時刻同期はAndroid OS側に丸投げしようと思っていたのですが、実際に運用していると筆者の環境ではシステム時計が2秒弱程度進むのを確認…
時刻同期のタイミングも不明で同期先のサーバも指定できないブラックボックスであり、これによって時計がズレるのは本来の使用用途からして許容できない為、アプリ側で同期することに。
3. opr-clock-androidを起動する
ビルドして署名したapkをGitHubリポジトリのReleaseに置いているので、LD290EJS-FPN1をお持ちの方はUSBフラッシュメモリに入れてOTGケーブルで接続してインストールすればすぐに使えます。

インストールすると opr-clock がランチャーに現れるので起動すると以下のような感じ。

ちなみに このアプリ、Android 7.1以上であれば ほとんどの機種で動作すると思います。ただし、パンチホールタイプのインカメラが付いている端末だとカメラの部分が欠けます。

Pixel 10 Proで起動したopr-clock。グリニッジ標準時の画面右側、「秒」の左上が欠けている。
そして、ウルトラワイドディスプレイではない端末で動かすと何も表示されないスペースが時計の下に出来てしまうので、他の機種で使う場合は適宜コードをいじって、他のタイムゾーンを追加して3段、4段にするとか、天気や気温など何か別の表示をするようにするとか、カスタマイズすると良いかなと思います。(MITライセンスなので、各々でフォークして良い感じにしてください。)
今回はあくまで LD290EJS-FPN1 で時計を表示しっぱなしにする目的で製作したため、タッチを活かした何らかの操作機能や設定画面などを省いた手抜き仕様です。気が向いたら他の機種でも使えるようなアップデートをした上でGoogle Play Storeに公開するかもしれません。
番外編:設置方法、どうしよう
壁付けかスタンドか、何らかのLD290EJS-FPN1用の固定具が欲しい… 裏の穴の寸法を測って作るか… https://t.co/OI5jbLbn71 pic.twitter.com/xdD75QQCOk
— けーいち (@9SQ) November 26, 2025
運よく LD290EJS-FPN1 を2枚購入できたので、1枚は会社に持っていって壁面サイネージの仲間にしてあげようと画策しているものの、裏の穴がVESA等の規格ではないため何らかの固定金具を作る必要がありそう。(これ専用の壁掛け金具などが公式で用意されているようですが、既に本体が販売終了のため入手経路が無い)
重量が2.8Kgあるため、一般的なタブレットスタンドのようなものでは保持力が足りず、現状は壁に立て掛けて下部に耐震ジェルを貼って仮固定しているような状況…
うまく設置できたら追記しようと思います。