User:Vazhnov Alexey/Record GNSS traces/Bluetooth and web panel

From OpenStreetMap Wiki
Jump to navigation Jump to search

Here is described more complex setup of User:Vazhnov Alexey/Record GNSS traces.

Hardware

All the hardware listed in the main page, User:Vazhnov Alexey/Record GNSS traces, except Bluetooth adapter:

Bluetooth

To configure connection between my SBC and smartphone.

I'm using this USB adapter on my SBC, USB-BT4 (CSR8510 A10):

Bus 003 Device 002: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)

Software

Packages

Install:

sudo apt-get -V install bluez bluez-tools

Pairing

Do your SBC visible:

sudo bt-adapter --set Powered 1
sudo bt-adapter --set DiscoverableTimeout 0
sudo bt-adapter --set Discoverable 1

sudo bt-device -l — list devices near your SBC. Remember MAC of your smartphone.

sudo bt-device --set fc:3d:93:75:1a:30 Trusted 1 — add MAC-address to "Trusted". Should return: Trusted: 0 -> 1.

Create a file /etc/bluetooth/bluez_pin.txt with MAC-address of your smartphone(s) and "asterisk" symbol, to allow connection without PIN:

FC:3D:93:75:1A:30	*

(you can use any path, just substitute it later)

Execute sudo chmod 640 /etc/bluetooth/bluez_pin.txt to avoid the message "Warning! /etc/bluetooth/bluez_pin.txt is world readable!".

Run agent manually sudo bt-agent -c DisplayYesNo and try to pair from smartphone.

On an Android phone:

  1. Android 9 / Lineageos 16: go to Settings → Connected devices → Connection preferences → Bluetooth
  2. enable Bluetooth
  3. press "Pair new device"
  4. wait till your device appears in the list
  5. press the line with the name of your SBC device
  6. answer "Pair" to the question "Pair with XXX?"
  7. find your device in the list Connected devices
  8. press the line with the name of your SBC device
  9. enable "Internet access"

pan0

Based on this answer from Logan Gunthorpe.

Create bridge interface with Systemd:

/etc/systemd/network/pan0.netdev:

[NetDev]
Name=pan0
Kind=bridge

/etc/systemd/network/pan0.network:

[Match]
Name=pan0

[Network]
Address=172.20.1.1/24
DHCPServer=yes

Services

/etc/systemd/system/bt-agent.service:

[Unit]
Description=Bluetooth auth agent
Requires=bluetooth.service
After=bluetooth.service
# To avoid infinite fail when USB adapter is not connected. But this check doesn't work in live, only on service start.
# As an alternative, use "bt-agent@hci0.service"
ConditionPathExists=/sys/class/bluetooth/hci0

[Service]
Type=simple
Restart=always
KillSignal=SIGUSR1
ExecStart=/usr/bin/bt-agent -c DisplayOnly -p /etc/bluetooth/bluez_pin.txt

[Install]
WantedBy=multi-user.target

/etc/systemd/system/bt-network.service:

[Unit]
Description=Bluetooth NEP PAN
After=pan0.network

[Service]
ExecStart=/usr/bin/bt-network -s nap pan0
Type=simple

[Install]
WantedBy=multi-user.target

Run all services

sudo systemctl enable systemd-networkd
sudo systemctl enable bt-agent
sudo systemctl enable bt-network
sudo service systemd-networkd start
sudo service bt-agent start
sudo service bt-network start

Zeroconf/Avahi

It would be great to use autoconfigured .local DNS-names. But, as I understand, Zeroconf/Avahi are not working through Bluetooth. So use IP-addresses.

Test

Bluetooth network connection doesn't work, when Wi-Fi enabled on smartphone. So:

  • disable Wi-Fi
  • enable Bluetooth
  • connect to SBC
  • ping IPv4-address 172.20.1.1 from smartphone (I use Termux for this)

Stream GNSS data to Android

Theoretically, it is possible to stream NMEA data to Android smartphone and use these data through location provider, like BlueGps. But BlueGps can't work with fresh Android: https://github.com/HvB/BlueGPS4Droid/issues/2

FlightGear as Bluetooth NMEA GPS provider — example how to configure a streaming: Linux, NMEA, sdptool, rfcomm → Android, Bluetooth GPS app.

Bluetooth troubleshooting

I don't see my device in "Pair new device" list
1. Check your adapter is in state discoverable. There is timeout 180 seconds by default, after this time it backs to undiscoverable state.
2. Check the list "Previously connected devices".
After button "Pair" pressed, nothing happens
check bt-network service status:
Aug 02 15:42:33 lime2 systemd[1]: /etc/systemd/system/bt-network.service:3: Failed to add dependency on pan0.network, ignoring: Unknown error -22
Aug 02 15:42:35 lime2 systemd[1]: /etc/systemd/system/bt-network.service:3: Failed to add dependency on pan0.network, ignoring: Unknown error -22
Aug 02 15:42:39 lime2 systemd[1]: /etc/systemd/system/bt-network.service:3: Failed to add dependency on pan0.network, ignoring: Unknown error -22

If this error happened, restart service:

sudo service bt-network restart

Known issues

Without a Bluetooth dongle (USB adapter), bt-agent is constantly restarting
Logs are:
Aug 15 12:10:12 lime2 bt-agent[2530]: **
Aug 15 12:10:12 lime2 bt-agent[2530]: ERROR:lib/helpers.c:319:intf_supported: assertion failed: (introspection_proxy != NULL)
Aug 15 12:10:12 lime2 systemd[1]: bt-agent.service: Main process exited, code=killed, status=6/ABRT
Aug 15 12:10:12 lime2 systemd[1]: bt-agent.service: Failed with result 'signal'.
Aug 15 12:10:12 lime2 systemd[1]: bt-agent.service: Service RestartSec=100ms expired, scheduling restart.
Aug 15 12:10:12 lime2 systemd[1]: bt-agent.service: Scheduled restart job, restart counter is at 19.
Aug 15 12:10:12 lime2 systemd[1]: Stopped Bluetooth Auth Agent.
Aug 15 12:10:12 lime2 systemd[1]: Condition check resulted in Bluetooth service being skipped.
Aug 15 12:10:12 lime2 systemd[1]: Started Bluetooth Auth Agent.
Aug 15 12:10:12 lime2 dbus-daemon[967]: [system] Activating via systemd: service name='org.bluez' unit='dbus-org.bluez.service' requested by ':1.49' (uid=0 pid=2558 comm="/usr/bin/bt-agent -c DisplayOnly -p /etc/bluetooth")
Aug 15 12:10:12 lime2 systemd[1]: Condition check resulted in Bluetooth service being skipped.
Aug 15 12:10:12 lime2 systemd[1]: Stopping Bluetooth Auth Agent...
Aug 15 12:10:12 lime2 systemd[1]: bt-agent.service: Main process exited, code=killed, status=10/USR1
Aug 15 12:10:12 lime2 systemd[1]: bt-agent.service: Failed with result 'signal'.
Aug 15 12:10:12 lime2 systemd[1]: Stopped Bluetooth Auth Agent.
Linux kernel exception happens when press "Forget" button
Currently I don't know what to do with this, maybe it is connected with drivers of Bluetooth adapter (USB-BT4: 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle / CSR8510 A10).
Aug  2 15:51:50 lime2 systemd-networkd[3030]: pan0: Configured
Aug  2 15:53:51 lime2 kernel: [ 2193.418356] pan0: port 1(bnep0) entered disabled state
Aug  2 15:53:51 lime2 kernel: [ 2193.432728] device bnep0 left promiscuous mode
Aug  2 15:53:51 lime2 kernel: [ 2193.432842] pan0: port 1(bnep0) entered disabled state
Aug  2 15:53:51 lime2 kernel: [ 2193.469182] ------------[ cut here ]------------
Aug  2 15:53:51 lime2 kernel: [ 2193.469319] WARNING: CPU: 0 PID: 6520 at fs/sysfs/group.c:281 sysfs_remove_group+0x67/0x6c
Aug  2 15:53:51 lime2 kernel: [ 2193.469360] sysfs group 'byte_queue_limits' not found for kobject 'tx-0'
Aug  2 15:53:51 lime2 kernel: [ 2193.469389] Modules linked in: pps_ldisc cmac bnep evdev btusb btintel btrtl lima axp20x_adc btbcm bluetooth gpu_sched axp20x_battery at24 sun4i_gpadc_iio ecdh_generic rfkill industrialio sunxi_cedrus(C) sun4i_ts ecc v4l2_mem2mem cdc_acm videobuf2_dma_contig videobuf2_memops videobuf2_v4l2 videobuf2_common zram uio_pdrv_genirq display_connector uio cpufreq_dt ip_tables x_tables autofs4 pinctrl_axp209 sun4i_gpadc sunxi phy_generic pwrseq_emmc micrel(E)
Aug  2 15:53:51 lime2 kernel: [ 2193.470553] CPU: 0 PID: 6520 Comm: kbnepd bnep0 Tainted: G         C  E     5.10.43-sunxi #21.05.6
Aug  2 15:53:51 lime2 kernel: [ 2193.470588] Hardware name: Allwinner sun7i (A20) Family
Aug  2 15:53:51 lime2 kernel: [ 2193.470712] [<c010ca1d>] (unwind_backtrace) from [<c010952d>] (show_stack+0x11/0x14)
Aug  2 15:53:51 lime2 kernel: [ 2193.470804] [<c010952d>] (show_stack) from [<c0972dbb>] (dump_stack+0x77/0x84)
Aug  2 15:53:51 lime2 kernel: [ 2193.470896] [<c0972dbb>] (dump_stack) from [<c011af05>] (__warn+0xad/0xc0)
Aug  2 15:53:51 lime2 kernel: [ 2193.470993] [<c011af05>] (__warn) from [<c096cd27>] (warn_slowpath_fmt+0x5f/0x7c)
Aug  2 15:53:51 lime2 kernel: [ 2193.471090] [<c096cd27>] (warn_slowpath_fmt) from [<c02f6bdf>] (sysfs_remove_group+0x67/0x6c)
Aug  2 15:53:51 lime2 kernel: [ 2193.471195] [<c02f6bdf>] (sysfs_remove_group) from [<c084ef4f>] (netdev_queue_update_kobjects+0xb3/0xe4)
Aug  2 15:53:51 lime2 kernel: [ 2193.471296] [<c084ef4f>] (netdev_queue_update_kobjects) from [<c084efc3>] (netdev_unregister_kobject+0x43/0x5c)
Aug  2 15:53:51 lime2 kernel: [ 2193.471396] [<c084efc3>] (netdev_unregister_kobject) from [<c082978b>] (rollback_registered_many+0x347/0x4e4)
Aug  2 15:53:51 lime2 kernel: [ 2193.471491] [<c082978b>] (rollback_registered_many) from [<c082997d>] (unregister_netdevice_queue+0x55/0xc4)
Aug  2 15:53:51 lime2 kernel: [ 2193.471582] [<c082997d>] (unregister_netdevice_queue) from [<c0829a03>] (unregister_netdev+0x17/0x20)
Aug  2 15:53:51 lime2 kernel: [ 2193.471707] [<c0829a03>] (unregister_netdev) from [<bf95d701>] (bnep_session+0x351/0x63c [bnep])
Aug  2 15:53:51 lime2 kernel: [ 2193.471873] [<bf95d701>] (bnep_session [bnep]) from [<c01345d5>] (kthread+0x109/0x10c)
Aug  2 15:53:51 lime2 kernel: [ 2193.471960] [<c01345d5>] (kthread) from [<c0100159>] (ret_from_fork+0x11/0x38)
Aug  2 15:53:51 lime2 kernel: [ 2193.472004] Exception stack(0xc3023fb0 to 0xc3023ff8)
Aug  2 15:53:51 lime2 kernel: [ 2193.472062] 3fa0:                                     00000000 00000000 00000000 00000000
Aug  2 15:53:51 lime2 kernel: [ 2193.472131] 3fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
Aug  2 15:53:51 lime2 kernel: [ 2193.472191] 3fe0: 00000000 00000000 00000000 00000000 00000013 00000000
Aug  2 15:53:51 lime2 kernel: [ 2193.472474] ---[ end trace 826d8e62c2f03bd3 ]---
Aug  2 15:53:51 lime2 kernel: [ 2193.472936] ------------[ cut here ]------------
Aug  2 15:53:51 lime2 kernel: [ 2193.473035] WARNING: CPU: 0 PID: 6520 at fs/sysfs/group.c:281 sysfs_remove_group+0x67/0x6c
Aug  2 15:53:51 lime2 kernel: [ 2193.473074] sysfs group 'power' not found for kobject 'bnep0'
Aug  2 15:53:51 lime2 kernel: [ 2193.473101] Modules linked in: pps_ldisc cmac bnep evdev btusb btintel btrtl lima axp20x_adc btbcm bluetooth gpu_sched axp20x_battery at24 sun4i_gpadc_iio ecdh_generic rfkill industrialio sunxi_cedrus(C) sun4i_ts ecc v4l2_mem2mem cdc_acm videobuf2_dma_contig videobuf2_memops videobuf2_v4l2 videobuf2_common zram uio_pdrv_genirq display_connector uio cpufreq_dt ip_tables x_tables autofs4 pinctrl_axp209 sun4i_gpadc sunxi phy_generic pwrseq_emmc micrel(E)
Aug  2 15:53:51 lime2 kernel: [ 2193.474207] CPU: 0 PID: 6520 Comm: kbnepd bnep0 Tainted: G        WC  E     5.10.43-sunxi #21.05.6
Aug  2 15:53:51 lime2 kernel: [ 2193.474242] Hardware name: Allwinner sun7i (A20) Family
Aug  2 15:53:51 lime2 kernel: [ 2193.474340] [<c010ca1d>] (unwind_backtrace) from [<c010952d>] (show_stack+0x11/0x14)
Aug  2 15:53:51 lime2 kernel: [ 2193.474424] [<c010952d>] (show_stack) from [<c0972dbb>] (dump_stack+0x77/0x84)
Aug  2 15:53:51 lime2 kernel: [ 2193.474511] [<c0972dbb>] (dump_stack) from [<c011af05>] (__warn+0xad/0xc0)
Aug  2 15:53:51 lime2 kernel: [ 2193.474609] [<c011af05>] (__warn) from [<c096cd27>] (warn_slowpath_fmt+0x5f/0x7c)
Aug  2 15:53:51 lime2 kernel: [ 2193.474705] [<c096cd27>] (warn_slowpath_fmt) from [<c02f6bdf>] (sysfs_remove_group+0x67/0x6c)
Aug  2 15:53:51 lime2 kernel: [ 2193.474802] [<c02f6bdf>] (sysfs_remove_group) from [<c064e92b>] (device_del+0x7f/0x2d0)
Aug  2 15:53:51 lime2 kernel: [ 2193.474902] [<c064e92b>] (device_del) from [<c082978b>] (rollback_registered_many+0x347/0x4e4)
Aug  2 15:53:51 lime2 kernel: [ 2193.474998] [<c082978b>] (rollback_registered_many) from [<c082997d>] (unregister_netdevice_queue+0x55/0xc4)
Aug  2 15:53:51 lime2 kernel: [ 2193.475088] [<c082997d>] (unregister_netdevice_queue) from [<c0829a03>] (unregister_netdev+0x17/0x20)
Aug  2 15:53:51 lime2 kernel: [ 2193.475204] [<c0829a03>] (unregister_netdev) from [<bf95d701>] (bnep_session+0x351/0x63c [bnep])
Aug  2 15:53:51 lime2 kernel: [ 2193.475322] [<bf95d701>] (bnep_session [bnep]) from [<c01345d5>] (kthread+0x109/0x10c)
Aug  2 15:53:51 lime2 kernel: [ 2193.475404] [<c01345d5>] (kthread) from [<c0100159>] (ret_from_fork+0x11/0x38)
Aug  2 15:53:51 lime2 kernel: [ 2193.475446] Exception stack(0xc3023fb0 to 0xc3023ff8)
Aug  2 15:53:51 lime2 kernel: [ 2193.475502] 3fa0:                                     00000000 00000000 00000000 00000000
Aug  2 15:53:51 lime2 kernel: [ 2193.475571] 3fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
Aug  2 15:53:51 lime2 kernel: [ 2193.475631] 3fe0: 00000000 00000000 00000000 00000000 00000013 00000000
Aug  2 15:53:51 lime2 kernel: [ 2193.475671] ---[ end trace 826d8e62c2f03bd4 ]---
Aug  2 15:53:51 lime2 kernel: [ 2193.475768] ------------[ cut here ]------------
Aug  2 15:53:51 lime2 kernel: [ 2193.476100] WARNING: CPU: 0 PID: 6520 at fs/sysfs/group.c:281 sysfs_remove_group+0x67/0x6c
Aug  2 15:53:51 lime2 kernel: [ 2193.476167] sysfs group 'statistics' not found for kobject 'bnep0'
Aug  2 15:53:51 lime2 kernel: [ 2193.476230] Modules linked in: pps_ldisc cmac bnep evdev btusb btintel btrtl lima axp20x_adc btbcm bluetooth gpu_sched axp20x_battery at24 sun4i_gpadc_iio ecdh_generic rfkill industrialio sunxi_cedrus(C) sun4i_ts ecc v4l2_mem2mem cdc_acm videobuf2_dma_contig videobuf2_memops videobuf2_v4l2 videobuf2_common zram uio_pdrv_genirq display_connector uio cpufreq_dt ip_tables x_tables autofs4 pinctrl_axp209 sun4i_gpadc sunxi phy_generic pwrseq_emmc micrel(E)
Aug  2 15:53:51 lime2 kernel: [ 2193.477908] CPU: 0 PID: 6520 Comm: kbnepd bnep0 Tainted: G        WC  E     5.10.43-sunxi #21.05.6
Aug  2 15:53:51 lime2 kernel: [ 2193.477978] Hardware name: Allwinner sun7i (A20) Family
Aug  2 15:53:51 lime2 kernel: [ 2193.478115] [<c010ca1d>] (unwind_backtrace) from [<c010952d>] (show_stack+0x11/0x14)
Aug  2 15:53:51 lime2 kernel: [ 2193.478276] [<c010952d>] (show_stack) from [<c0972dbb>] (dump_stack+0x77/0x84)
Aug  2 15:53:51 lime2 kernel: [ 2193.478380] [<c0972dbb>] (dump_stack) from [<c011af05>] (__warn+0xad/0xc0)
Aug  2 15:53:51 lime2 kernel: [ 2193.478477] [<c011af05>] (__warn) from [<c096cd27>] (warn_slowpath_fmt+0x5f/0x7c)
Aug  2 15:53:51 lime2 kernel: [ 2193.478577] [<c096cd27>] (warn_slowpath_fmt) from [<c02f6bdf>] (sysfs_remove_group+0x67/0x6c)
Aug  2 15:53:51 lime2 kernel: [ 2193.478666] [<c02f6bdf>] (sysfs_remove_group) from [<c02f6bfd>] (sysfs_remove_groups+0x19/0x24)
Aug  2 15:53:51 lime2 kernel: [ 2193.478761] [<c02f6bfd>] (sysfs_remove_groups) from [<c064de23>] (device_remove_attrs+0x2f/0x50)
Aug  2 15:53:51 lime2 kernel: [ 2193.478850] [<c064de23>] (device_remove_attrs) from [<c064e9ab>] (device_del+0xff/0x2d0)
Aug  2 15:53:51 lime2 kernel: [ 2193.478949] [<c064e9ab>] (device_del) from [<c082978b>] (rollback_registered_many+0x347/0x4e4)
Aug  2 15:53:51 lime2 kernel: [ 2193.479046] [<c082978b>] (rollback_registered_many) from [<c082997d>] (unregister_netdevice_queue+0x55/0xc4)
Aug  2 15:53:51 lime2 kernel: [ 2193.479136] [<c082997d>] (unregister_netdevice_queue) from [<c0829a03>] (unregister_netdev+0x17/0x20)
Aug  2 15:53:51 lime2 kernel: [ 2193.479256] [<c0829a03>] (unregister_netdev) from [<bf95d701>] (bnep_session+0x351/0x63c [bnep])
Aug  2 15:53:51 lime2 kernel: [ 2193.479378] [<bf95d701>] (bnep_session [bnep]) from [<c01345d5>] (kthread+0x109/0x10c)
Aug  2 15:53:51 lime2 kernel: [ 2193.479464] [<c01345d5>] (kthread) from [<c0100159>] (ret_from_fork+0x11/0x38)
Aug  2 15:53:51 lime2 kernel: [ 2193.479508] Exception stack(0xc3023fb0 to 0xc3023ff8)
Aug  2 15:53:51 lime2 kernel: [ 2193.479567] 3fa0:                                     00000000 00000000 00000000 00000000
Aug  2 15:53:51 lime2 kernel: [ 2193.479635] 3fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
Aug  2 15:53:51 lime2 kernel: [ 2193.479696] 3fe0: 00000000 00000000 00000000 00000000 00000013 00000000
Aug  2 15:53:51 lime2 kernel: [ 2193.479743] ---[ end trace 826d8e62c2f03bd5 ]---
Aug  2 15:53:51 lime2 systemd-networkd[3030]: bnep0: Lost carrier
Aug  2 15:53:51 lime2 avahi-daemon[981]: Interface bnep0.IPv6 no longer relevant for mDNS.
Aug  2 15:53:51 lime2 systemd-networkd[3030]: pan0: Lost carrier
Aug  2 15:53:51 lime2 networkd-dispatcher[989]: Failed to request link: No such device

Control web-interface

Cockpit

To manage system services, probably it is easier to use Cockpit.

sudo apt-get -V -t buster-backports install cockpit

Check locally with web-browser or, for example, with curl:

 $ curl -k -w '\n' 'https://lime2.local:9090/ping'
{ "service": "cockpit" }

Simple Python Flask web server

Written in Python + Flask. State: very beginning.

sudo apt-get -V install python3-venv python3-pip python3-setuptools python3-psutil
sudo adduser --system --group --home /var/lib/gnss_web_control --disabled-password --gecos "GNSS HTTP control panel" gnss_web_control
sudo visudo -f /etc/sudoers.d/gnss_web_control

Content:

gnss_web_control ALL = NOPASSWD: /sbin/shutdown, /usr/bin/killall -u gpsd, /usr/sbin/service gpspipe *, /usr/sbin/service gpsd *

Then:

sudo -u gnss_web_control -H bash
cd
python3 -m venv --system-site-packages venv-flask
source ~/venv-flask/bin/activate
echo "$VIRTUAL_ENV"   # To check venv
git clone 'https://gitlab.com/vazhnov/gnss-web-control.git' 'code-repository'
cd ~/code-repository
pip3 install -r requirements.txt

Then create /etc/systemd/system/flask-app.service (to listen IPv4 only, replace "::" to 0.0.0.0):

[Unit]
Description=Flask GNSS web control
Documentation=https://wiki.openstreetmap.org/wiki/User:Vazhnov_Alexey/Record_GNSS_traces/Bluetooth_and_web_panel
After=network.target

[Service]
Type=simple
User=gnss_web_control
WorkingDirectory=/var/lib/gnss_web_control/code-repository
Environment=FLASK_APP=gnss-flask-control.py FLASK_ENV=development FLASK_DEBUG=1
ExecStart=/var/lib/gnss_web_control/venv-flask/bin/flask run -p 8080 -h ::
Restart=on-failure
MemoryMax=200M

[Install]
WantedBy=multi-user.target

Then:

sudo systemctl enable flask-app
sudo service flask-app start
sudo service flask-app status

webgps.py

webgps.py is a Python client example from gpsd package. It generates HTML page with information about satellites.

It is better to run it continuously in background, see comment here:

For best results, webgps should be run soon after the start of gpsd with duration c. This should minimize the load on the machine and maximize the ability of webgps to provide a complete display. The HTML file is updated roughly every second and the JavaScript file updates every 5 or 10 seconds. The HTML specifically updates every time a TPV or SKY sentence is sent by gpsd while JavaScript is only updated for some SKY sentences.

If a duration is missing, the current skyview is generated and webgps.py exits immediately. This is the same as giving a duration of 0. Also, in this case, webgps will pick up only the first TPV or SKY sentence rather than a complete dataset.

Create unit:

sudo systemctl edit --force --full webgps.service
[Unit]
Description=Generate HTML page with GNSS information from GPSD
Documentation=https://wiki.openstreetmap.org/wiki/User:Vazhnov_Alexey/Record_GNSS_traces/Bluetooth_and_web_panel
# Name `gps0` is set in `/lib/udev/rules.d/60-gpsd.rules` and usually points to `/dev/ttyACM0`.
ConditionPathExists=/dev/gps0
Requires=gpsd.service

[Service]
Type=simple
Restart=always
MemoryMax=100M
User=gnss_scripts
Group=gnss_scripts
EnvironmentFile=/etc/default/gnss_scripts
ExecStartPre=mkdir -pv "$WEBGPS_WORKDIR"
ExecStart=sh -c 'cd "$WEBGPS_WORKDIR"; python3 /var/lib/gnss_web_control/code-repository/gpsd-client/webgps.py $WEBGPS_ARGS'

[Install]
WantedBy=multi-user.target
sudo systemctl enable webgps.service