Broadcasting GPS on the local network
Broadcasting GPS on the local network
在本地网络广播 GPS 信号
May 03, 2026 2026年5月3日
Ever since Mozilla killed its GPS location service, GPS hasn’t been very accurate for me on Linux. The system on linux that handles location on many linux systems is called Geoclue, and this system is used by for example Firefox and Gnome Maps (notably not Chrome). 自从 Mozilla 终止了其 GPS 定位服务后,我在 Linux 上的 GPS 定位一直不太准确。在许多 Linux 系统中,负责处理定位的系统被称为 Geoclue,Firefox 和 Gnome Maps(值得注意的是 Chrome 不使用它)等应用都在使用该系统。
Based on the output of /usr/libexec/geoclue-2.0/demos/where-am-i, it uses a GeoIP database which places me somewhere in Toronto with 25KM accuracy:
根据 /usr/libexec/geoclue-2.0/demos/where-am-i 的输出,它使用的是 GeoIP 数据库,将我的位置定位在多伦多附近,精度仅为 25 公里:
/usr/libexec/geoclue-2.0/demos/where-am-i
Client object: /org/freedesktop/GeoClue2/Client/1
New location: Latitude: 43.706400° Longitude: -79.398600°
Accuracy: 25000 meters
Description: GeoIP (ichnaea)
Timestamp: Sun 03 May 2026 04:00:10 PM (1777838410 seconds since the Epoch)
Note: to install where-am-i, you might need to run:
注意:要安装 where-am-i,你可能需要运行:
# Fedora
sudo dnf install geoclue2-demos
# Debian family
sudo apt install geoclue-2-demo
I could try to find an alternative service (suggestions welcome!), but I have some servers at home, and it made me wonder if there’s something I can run locally. The servers don’t move, so the logic was that as long as I’m on the home network, I can just decide what GPS coordinates to emit. 我本可以尝试寻找替代服务(欢迎提供建议!),但我家里有一些服务器,这让我想到是否可以运行本地服务。服务器是固定不动的,所以逻辑很简单:只要我在家庭网络中,我就可以自行决定广播哪些 GPS 坐标。
Turns out, there is! The protocol is called NMEA 0183, which appears to be a suite of specifications for marine electronics (ships!). The messages can be sent over a serial port or over a TCP socket. For example, a message with GPS information might look like this: 事实证明,确实可以!该协议被称为 NMEA 0183,它似乎是一套用于海洋电子设备(船舶!)的规范。这些消息可以通过串口或 TCP 套接字发送。例如,包含 GPS 信息的报文可能如下所示:
$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
It’s also support, and enabled by default by GeoClue. The settings in /etc/geoclue/geoclue.conf look like this for me:
GeoClue 也支持该协议,并且默认处于启用状态。我的 /etc/geoclue/geoclue.conf 设置如下:
# Network NMEA source configuration options
[network-nmea]
# Fetch location from NMEA sources on local network?
enable=true
The way GeoClue does the look up, is that it searches for an MDNS entry for a service called _nmea-0183._tcp. If it finds one, it connects to the address in the record and gets the GPS information. So, I figured I could just write a small server (with some help from Claude) that emits these lines and registers itself with Avahi (the standard MDNS implementation on Linux, or a Mac it would be Bonjour).
GeoClue 的查找方式是搜索名为 _nmea-0183._tcp 的 MDNS 条目。如果找到,它就会连接到记录中的地址并获取 GPS 信息。因此,我想我可以写一个小服务器(在 Claude 的帮助下),让它发送这些数据行,并向 Avahi(Linux 上的标准 MDNS 实现,在 Mac 上则是 Bonjour)注册自己。
MDNS is also the thing that lets you use .local addresses on the local network, or discover things like printers, TVs and so on.
MDNS 也是让你能够在本地网络中使用 .local 地址,或发现打印机、电视等设备的技术。
I shared this on Github: https://github.com/evert/nmea-static-gps-server/blob/main/nmea_static_gps_server.py. This is the TCP server that emits the GPS info once per second. The repo also includes Avahi configuration that looks like: 我已将其分享在 Github 上:https://github.com/evert/nmea-static-gps-server/blob/main/nmea_static_gps_server.py。这是一个每秒发送一次 GPS 信息的 TCP 服务器。该仓库还包含如下的 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>
After this file is copied to /etc/avahi/services/nmea-statis-gpc.service, you can test on other machines to see if the record can be discovered with:
将此文件复制到 /etc/avahi/services/nmea-statis-gpc.service 后,你可以在其他机器上测试该记录是否能被发现:
$ avahi-browse _nmea-0183._tcp -r -t
In my case the service is running on a machine called node05.local. The service itself can easily be tested with telnet:
在我的例子中,该服务运行在名为 node05.local 的机器上。该服务本身可以通过 telnet 轻松测试:
$ telnet node05.local 10110
Once this is all in place, I just had to restart Geoclue on the client machine and it started picking up the GPS coordinates from the server: 一旦一切就绪,我只需在客户端机器上重启 Geoclue,它就开始从服务器获取 GPS 坐标了:
$ sudo systemctl restart geoclue
$ /usr/libexec/geoclue-2.0/demos/where-am-i
Which gave the exact coordinates from the server! 结果显示了来自服务器的精确坐标!
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)
A quick test with Gnome Maps also immediately showed the correct location. Firefox needed a restart for me. 使用 Gnome Maps 进行快速测试,也立即显示了正确的位置。Firefox 则需要重启才能生效。
Now I never have to wait for a slower, inaccurate GPS lookup again and as long as I’m home all my Linux machines will just instantly pick up the correct location. It also seemed to work on Apple Maps on a Mac, but only when Location Services was turned off. I didn’t get an exact dot on the map but it got the area right. 现在我再也不用等待缓慢且不准确的 GPS 定位了,只要我在家,我所有的 Linux 机器都能瞬间获取到正确的位置。它似乎在 Mac 的 Apple Maps 上也能用,但前提是必须关闭“定位服务”。虽然地图上没有显示精确的蓝点,但它定位的区域是正确的。
For fun, you could also use this to spoof incorrect locations to your Linux-using guests and co-workers. Hope this tool is useful to anyone else. If you’d like to contribute, more/better setup instructions for other distros are appreciated (if they are different). 出于娱乐目的,你甚至可以用它向使用 Linux 的访客或同事伪造错误的位置。希望这个工具对其他人也有用。如果你愿意贡献代码,欢迎提供针对其他发行版的更多/更好的设置说明(如果它们有所不同的话)。
Link once more: https://github.com/evert/nmea-static-gps-server 再次附上链接:https://github.com/evert/nmea-static-gps-server