ローカルネットワークでGPSをブロードキャストする
(evertpot.com)- MozillaのGPS location service終了後、LinuxのGeoClueベースの位置特定の精度が低下し、
where-am-iはGeoIPでToronto近辺を25km精度で示していた - 固定されたホームサーバーは動かないことを利用し、自宅ネットワーク内で任意のGPS座標をローカルに配信するよう構成した
- GeoClueは
/etc/geoclue/geoclue.confでnetwork-nmeaがデフォルトで有効になっており、_nmea-0183._tcpmDNSサービスを見つけてGPS情報を受け取っていた - nmea-static-gps-serverは1秒に1回 NMEA 0183 GPSメッセージをTCPで配信し、Avahiで
_nmea-0183._tcpサービスを登録する - GeoClueを再起動するとクライアントがすぐにサーバーの座標を取得し、結果として
GPS GGA+RMCという説明と0 metersの精度が返され、Gnome Mapsは即座に正しい位置を表示した
GeoClueとNMEAの設定
- MozillaのGPS location service終了以降、Linuxでは位置精度が低下し、複数のLinuxシステムでFirefoxやGnome Mapsが利用するGeoClueは、
where-am-iベースでGeoIPによりToronto近辺を25km精度で示していた where-am-iデモはディストリビューションごとのパッケージとしてインストールできる# Fedora sudo dnf install geoclue2-demos # Debian family sudo apt install geoclue-2-demo- 固定されたホームサーバーは動かないことを利用して、自宅ネットワーク内では任意のGPS座標をローカルで配信するよう構成した
- 使用したプロトコルはNMEA 0183で、船舶用電子機器向けの仕様群であり、メッセージはシリアルポートまたはTCPソケットで送ることができる
- 例のGPSメッセージは
GPRMCとGPGGAの行で構成される$GPRMC,204049.000,A,5308.3999,N,00601.9266,E,0.000,0.000,030526,,*02 $GPGGA,204049.000,5308.3999,N,00601.9266,E,1,08,1.0,119.0,M,0.0,M,,*6F - GeoClueでは
/etc/geoclue/geoclue.confでnetwork-nmeaがデフォルトで有効になっていた# Network NMEA source configuration options [network-nmea] # Fetch location from NMEA sources on local network? enable=true - GeoClueは
_nmea-0183._tcpというmDNSサービスを探し、レコードを見つけるとそのアドレスへ接続してGPS情報を受け取る
サーバー実装と動作確認
- nmea-static-gps-serverは1秒ごとにGPS情報を配信するTCPサーバーで、Avahiによって
_nmea-0183._tcpサービスを登録する - AvahiはLinuxの標準的なmDNS実装で、MacではBonjourが同じ役割を担い、mDNSはローカルネットワーク上の
.localアドレスやプリンター・テレビのような機器の検出にも使われる - リポジトリには次のようなAvahiサービス設定が含まれている
<?xml version="1.0" standalone='no'?> <!DOCTYPE service-group SYSTEM "avahi-service.dtd"> <service-group> <name replace-wildcards="yes">NMEA GPS (%h)</name> <service> <type>_nmea-0183._tcp</type> <port>10110</port> </service> </service-group> - このファイルを
/etc/avahi/services/nmea-statis-gpc.serviceにコピーした後、別のマシンでavahi-browseを使ってサービス検出を確認できる$ avahi-browse _nmea-0183._tcp -r -t + wlp192s0 IPv6 NMEA GPS (node05) _nmea-0183._tcp local + wlp192s0 IPv4 NMEA GPS (node05) _nmea-0183._tcp local = wlp192s0 IPv6 NMEA GPS (node05) _nmea-0183._tcp local hostname = [node05.local] address = [fe80::a8c2:15de:9af:19b] port = [10110] txt = [] = wlp192s0 IPv4 NMEA GPS (node05) _nmea-0183._tcp local hostname = [node05.local] address = [192.168.2.205] port = [10110] txt = [] - サービスが
node05.localで動作している場合、telnet node05.local 10110でTCPサーバー自体も簡単にテストできる - クライアントでGeoClueを再起動すると、すぐにサーバーの座標を取得した
$ sudo systemctl restart geoclue $ /usr/libexec/geoclue-2.0/demos/where-am-i - 結果はサーバーの正確な座標と
GPS GGA+RMCという説明を返し、精度は0 metersと表示されたClient object: /org/freedesktop/GeoClue2/Client/3 New location: Latitude: 43.645758° Longitude: -79.410510° Accuracy: 0 meters Altitude: 119.000000 meters Speed: 0.000000 meters/second Description: GPS GGA+RMC Timestamp: Sun 03 May 2026 04:58:58 PM (1777841938 seconds since the Epoch) - Gnome Mapsはすぐに正しい位置を表示し、Firefoxは再起動が必要だった
- MacのApple MapsでもLocation Servicesをオフにした状態で動作しているように見えたが、地図上に正確な点は表示されず、おおよその地域だけが合っていた
- この方法により、自宅にいる間はLinuxマシンが遅く不正確なGPS検索を待たずに正しい位置を即座に取得でき、Linuxを使うゲストや同僚に対して誤った位置をスプーフィングする用途にも使える
- https://github.com/evert/nmea-static-gps-server
1件のコメント
Lobste.rs の意見
LAN 上で GNSS をアドバタイズできる標準の mDNS サービスがあるなんてまったく知らなかったが、これでここ半年ほど断続的に悩んでいた問題が一発で解決した
GPS 位置情報のスプーフィングは良いアイデアだが、実際に実装するとなると比較的かなり手間がかかりそう
Android の設定や Firefox 拡張機能に「実際の位置を使う / カスタム位置を使う」みたいな単純なオプションがあればいいのにと思う
ただ、IP やロケールのような他の要素と衝突したときに、GPS 位置情報にどれくらい大きな重みが与えられるのかも気になる
追記すると、ページ最下部で Jeff Geerling の写真を見て一瞬驚いたが、著者ではなく「いいね」を押しただけだと後から気づいた
できれば彼の仕事は普段あまり見ないようにしている
以前 Trimble の GNSS 受信機を使っていたが、USB OTG だったのか BLE だったのかは覚えていないものの、Trimble アプリが Mock Locations のソースになって、任意の Android アプリがスマホ本体の比較的低精度な位置情報ではなく、測量ポールの高精度な座標、約 2cm レベルを受け取れるようになっていた
面白いが、自分で実装して、ホームネットワークにいるときに Android 端末からこれを配信するスクリプトを作ることもできそう
まだ本当に必要かどうかまでは完全には確信できていない :p
NMEA 0183 が海洋電子機器向けの仕様群だというのは初めて知った
NMEA が何の略か調べるほど気にしたことはなかったが、ModemManager と Qualcomm モデム経由で名前自体は知っていた