Device location
atcd can send the position of a device to atc-server, which shows it on the
console map. atcd does not read GPS hardware. A process of yours sends the
position to atcd with the command atcd attr set-location.
Only an enrolled device that pulls from atc-server sends a position.
Send a position with atcd attr set-location
atcd attr set-location sends one position to the running atcd over the
control socket, as atcd attr set does. atcd checks the position and applies
the location.* send rules. A queued position goes out in the next report
and shows on the console map. A throttled position waits until the interval
ends. atcd does not send a too_close or an unchanged position. See
Outcomes and exit codes.
atcd attr set-location --lat 39.7392 --lon -104.9903 --accuracy-m 8
| Option | Required | Meaning |
|---|---|---|
--lat | yes | Latitude in degrees, from -90 to 90. |
--lon | yes | Longitude in degrees, from -180 to 180. |
--accuracy-m | no | The accuracy estimate in metres, 0 or more. |
--timestamp | no | When the position was measured, RFC 3339. If it is absent, atcd uses the time it read the request. |
--socket | no | The control socket. The default is /run/atcd/atcd.sock. |
Add the global option --json for a JSON answer: {"outcome": "queued"}.
One call for each location.min_interval_secs is enough. Inside the interval,
atcd holds the newest position. When the interval ends, atcd sends it if it
moved far enough. A more frequent call replaces the held position. Each call
is one process start and one connection.
Who can run it
The command needs access to the control socket. The socket has mode 0660.
On a non-root atcd, root and the members of the group of the daemon user have
access. Use the least privilege that works:
- Run the sender as root or as the daemon user (
atcby default). - Or give the GPS user one sudo rule. It lets that user run only this subcommand as the daemon user:
<gps-user> ALL=(<daemon user>) NOPASSWD: /usr/local/bin/atcd attr set-location *
The path is daemon.remote_path, /usr/local/bin/atcd by default. On a root
atcd, bootstrap gives the control socket to the SSH login user of the install,
with the group root. So on a root atcd the sudo rule names root, or the
sender runs as that login user.
Adding the GPS user to the group of the daemon user also gives access. It gives much more.
A member of that group can run every operation that the control
mode allows. On a direct_allowed device, this includes pushes, activations
and recovery. On a server_only device, it includes diagnostics, atcd attr
and atcd attr set-location. The group is also the group of the store. Under
hook isolation, the install gives the group %<group> ALL=(<hook user>) NOPASSWD: ALL. So a member can run any command as the hook user, whatever the
control mode.
Do not use the group for a sender that only needs to send a position.
Outcomes and exit codes
On success the command prints position sent to atcd: <meaning>:
| Outcome | Meaning |
|---|---|
queued | queued, goes out with the next report |
throttled | held until location.min_interval_secs has passed since the last send, then checked against location.min_distance_m again |
too_close | not sent, closer than location.min_distance_m to the last send |
unchanged | not sent, the same as the last send |
| Exit code | Meaning |
|---|---|
| 0 | atcd took the position. Any outcome gives 0. |
| 4 | atcd refused it. Causes: a bad position, for example atcd refused: lat must be from -90 to 90, got 95; location.enabled is false; this atcd runs no location reader because it does not pull from atc-server; or an atcd that has atcd attr but not this command, which answers “unknown attributes verb 4; update atcd”. |
| 3 | Nothing accepts a connection on the socket. |
| 5 | atcd accepted the connection and did not answer: a timeout or a hang-up. |
| 1 | atcd could not run it, or the atcd is older than atcd attr. A fault means the location input of atcd is busy, gone or stopped, or did not answer in 10 s. In the last case atcd may still send the position. |
After an upgrade
An earlier dev build read positions from a location socket,
/run/atcd/location.sock, and from the command atcd location set. Both are
gone. A connect to a leftover location.sock fails with “connection refused”.
Move the sending process to atcd attr set-location.
The earlier build also left three things on a device. They grant and hold nothing now. Install and update never create or remove them. Uninstall removes the drop-in with the unit, and keeps the group and the folder:
- the group
atc-location; - the drop-in
atc-location-group.confin/etc/systemd/system/<service>.service.d/; - the folder
/var/lib/atc-location.
In these paths and commands, <service> is the daemon.service_name of the
device, atcd by default. An install by the socket release named the group in
the main unit, /etc/systemd/system/<service>.service, on its
SupplementaryGroups= line. Only
an update of an older unit added the drop-in. A device can have either one.
atc bootstrap atcd update keeps the group and the drop-in. A unit that names
the group fails to start without it, so do not delete the group alone. To
remove the group, use this order:
- If the drop-in
atc-location-group.confis there, delete it. - Take
atc-locationout ofSupplementaryGroups=in the main unit. - Run
sudo systemctl daemon-reload. - Run
systemctl show -p SupplementaryGroups <service>. If the command fails, or its output still namesatc-location, stop here. Find the file that names the group, fix it, and go back to step 3. - Restart atcd:
sudo systemctl restart <service>. - Run
sudo groupdel atc-location.
The folder can hold files of your own. To remove it, stop the process that
wrote position.json. Delete position.json and position.json.tmp. Remove
the folder only if it is empty.
Settings
Four device settings control what atcd sends. They are not in atc.toml.
| Setting | Default | Meaning |
|---|---|---|
location.enabled | true | Set it to false to stop the device from sending a position. atcd then refuses each position with a reason. |
location.min_interval_secs | 60 | atcd sends a position at most once in this many seconds. |
location.min_distance_m | 25 | atcd does not send a move shorter than this many metres. |
location.precision_decimals | 5 | atcd rounds lat and lon to this many decimal places before it sends them. 5 is about 1 m, 3 is about 100 m. The maximum is 7. |
atcd applies the rules in this order: it rounds the position, checks the interval, then checks the distance.
An enrolled device refuses atc ota settings set from a laptop, because it
accepts changes only from the server. So set a value on the device, as the
account that runs atcd (atc by default):
sudo -u atc atcd settings set location.min_interval_secs=300
atcd reads its settings only when it starts. Restart it to apply the value:
sudo systemctl restart atcd
An earlier release read the position from a file, set by location.file. atcd
reads no file now, and skips a stored location.file row.
What the server does
atcd sends the position in the location section of its report. atc-server
keeps only the latest position of each device. A position with an older
timestamp than the stored one does not replace it.
When location.enabled is false, atcd stops sending new positions. The
server keeps the last position it stored.
An organization can turn location off for all its devices. The server then deletes the stored positions, drops new ones, and hides the map. The device still sends its reports.
An atc-server older than this feature accepts the report and drops the
position. It does not acknowledge the section. atcd then holds the position
for one hour. In that hour it sends no new position to that server. After the
hour it sends the newest position in one report, and holds again. The counter
atcd.pull.location_unacked_total counts each such report.
Telemetry
atcd.location.read_total{outcome} counts each position once, by the outcome
atcd answered: queued, throttled, too_close, unchanged, parse_error
and disabled.
It counts disabled once at start, and once for each position refused for
it.
The map
The console map uses OpenStreetMap tiles. It shows the credit “© OpenStreetMap contributors”.