irlmap.live Log in with Twitch

GPS from a BELABOX

If one of the modems in your BELABOX has GPS, you can use it as your location source and leave your phone out of it. One command sets it up.

Not sure your modem has GPS? Your phone works great and takes two minutes.

BELABOX is a separate open-source project (belabox.net). This installer is made by irlmap.live, not by the BELABOX team, and isn’t endorsed by them. It only uses ModemManager, which BELABOX already ships with, and doesn’t change anything in BELABOX itself.

What you need

Install it

SSH into your BELABOX and run this. It asks for your ingest token, which you’ll find under Settings → GPS apps and devices once you’re logged in.

curl -fsSL https://irlmap.live/install/belabox.sh | sudo sh

SSH into your BELABOX and run this. Your ingest token is already in it, so there’s nothing to type.

curl -fsSL https://irlmap.live/install/belabox.sh | sudo sh -s -- in_your_ingest_token

The installer:

  1. Finds the modem that has GPS (if you have several, it picks the one that supports it).
  2. Checks your token with irlmap.live before changing anything.
  3. Installs a small service that reads the position every two seconds and sends it. It starts at boot and restarts itself if it ever stops.
  4. Waits for the first GPS fix and tells you whether it got one.

Afterwards, the connection check under Settings turns green as soon as a location arrives. To remove it again:

curl -fsSL https://irlmap.live/install/belabox.sh | sudo sh -s -- --uninstall

No fix?

The first fix can take a couple of minutes. Indoors it often never comes, so test by a window or outside. The service keeps trying in the background, so you don’t need to run the installer again.

Sees satellites but never gets a position? That’s usually not the antenna. Some modems only work out a position while a location session is running, and enabling GPS through ModemManager (which the installer does) is what starts one. Just reading the modem’s NMEA port isn’t enough. If the satellites all show no signal at all, then it is the antenna: check the port, and make sure it can see the sky.

You can watch what the modem sees with mmcli -m any --location-get.

Good to know

The script

It’s good practice to read a script before you pipe it into sudo sh. Here’s the whole thing, or download it.

#!/bin/sh
# irlmap.live installer for BELABOX (or any Linux box that uses ModemManager).
# Made by irlmap.live. Not part of, affiliated with or endorsed by the BELABOX project.
#
# Sends the GPS position from your modem to irlmap.live every 2 seconds.
#
#   Install:    curl -fsSL https://irlmap.live/install/belabox.sh | sudo sh
#   With token: curl -fsSL https://irlmap.live/install/belabox.sh | sudo sh -s -- in_yourtoken
#   Remove:     curl -fsSL https://irlmap.live/install/belabox.sh | sudo sh -s -- --uninstall
#
# What it installs:
#   /etc/irlmap-gps.conf                    your token (readable by root only)
#   /usr/local/bin/irlmap-gps               the sender
#   /etc/systemd/system/irlmap-gps.service  starts it at boot, restarts it if it stops
set -eu

URL="https://irlmap.live"
CONF="/etc/irlmap-gps.conf"
BIN="/usr/local/bin/irlmap-gps"
UNIT="/etc/systemd/system/irlmap-gps.service"

say()  { printf '%s\n' "$*"; }
step() { printf '\n\033[1m==> %s\033[0m\n' "$*"; }
die()  { printf '\n\033[31mError:\033[0m %s\n' "$*" >&2; exit 1; }

# Questions come from the terminal even though the script itself arrives through a pipe.
ask() {
  printf '%s' "$1" >/dev/tty
  read -r REPLY </dev/tty || REPLY=""
}

# ---------------------------------------------------------------- uninstall
if [ "${1:-}" = "--uninstall" ]; then
  [ "$(id -u)" -eq 0 ] || die "Run it with sudo."
  systemctl disable --now irlmap-gps 2>/dev/null || true
  rm -f "$UNIT" "$BIN" "$CONF"
  systemctl daemon-reload 2>/dev/null || true
  say "irlmap.live GPS sender removed."
  exit 0
fi

say ""
say "irlmap.live GPS installer"
say "Sends your modem's GPS to irlmap.live. Only used while you're live on Twitch."

# ---------------------------------------------------------------- checks
[ "$(id -u)" -eq 0 ] || die "Run it with sudo:  curl -fsSL $URL/install/belabox.sh | sudo sh"
command -v mmcli >/dev/null 2>&1 || die "mmcli (ModemManager) wasn't found. This installer needs a modem managed by ModemManager, which is what BELABOX uses."
command -v curl  >/dev/null 2>&1 || die "curl wasn't found. Install it first (apt install curl)."

# ---------------------------------------------------------------- find a GPS modem
step "Looking for a modem with GPS"
GPS_MODEM=""
for m in $(mmcli -L 2>/dev/null | sed -n 's|.*/Modem/\([0-9]*\).*|\1|p'); do
  name=$(mmcli -L 2>/dev/null | sed -n "s|.*/Modem/$m \(.*\)|\1|p")
  if mmcli -m "$m" --location-status 2>/dev/null | grep -q 'gps-raw'; then
    say "  Modem $m: $name  (has GPS)"
    [ -n "$GPS_MODEM" ] || GPS_MODEM="$m"
  else
    say "  Modem $m: $name  (no GPS)"
  fi
done
[ -n "$GPS_MODEM" ] || die "None of your modems report GPS support. Check that the modem has a GNSS receiver, or send GPS from your phone instead: $URL/guides/phone-gps-irl-stream"

# ---------------------------------------------------------------- token
step "Your ingest token"
TOKEN="${1:-}"
if [ -z "$TOKEN" ]; then
  say "Find it on $URL/settings under \"GPS apps and devices\". It starts with in_"
  ask "Paste your ingest token: "
  TOKEN=$(printf '%s' "$REPLY" | tr -d '[:space:]')
fi
case "$TOKEN" in in_?*) ;; *) die "That doesn't look like an ingest token. It should start with in_" ;; esac

# An empty post is accepted by a valid token and rejected (401) by anything else.
code=$(curl -s -o /dev/null -w '%{http_code}' -m 10 -X POST "$URL/ingest" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{}' || true)
case "$code" in
  200) say "  Token works." ;;
  401) die "irlmap.live doesn't know that token. Copy it again from $URL/settings (it changes if you rotate it)." ;;
  *)   die "Couldn't reach irlmap.live (HTTP $code). Check the box has internet and try again." ;;
esac

# ---------------------------------------------------------------- install
step "Installing"
mkdir -p "$(dirname "$CONF")" "$(dirname "$BIN")" "$(dirname "$UNIT")"
umask 077
printf 'TOKEN=%s\nURL=%s\n' "$TOKEN" "$URL" > "$CONF"
umask 022

cat > "$BIN" <<'SENDER'
#!/bin/sh
# irlmap.live GPS sender. Reads the modem's GPS through ModemManager and posts it every 2 s.
# Settings live in /etc/irlmap-gps.conf. Installed by https://irlmap.live/install/belabox.sh
. /etc/irlmap-gps.conf
MODEM=""
n=0

# Modem numbers change when a modem resets, so look the GPS modem up again whenever needed.
find_modem() {
  for m in $(mmcli -L 2>/dev/null | sed -n 's|.*/Modem/\([0-9]*\).*|\1|p'); do
    if mmcli -m "$m" --location-status 2>/dev/null | grep -q 'gps-raw'; then MODEM="$m"; return 0; fi
  done
  MODEM=""
  return 1
}

while true; do
  if [ -z "$MODEM" ] || [ $((n % 30)) -eq 0 ]; then
    # Find the modem and (re)enable GPS about once a minute: a modem reset turns it off again.
    if find_modem; then
      mmcli -m "$MODEM" --location-enable-gps-raw --location-enable-gps-nmea >/dev/null 2>&1 || true
    fi
  fi
  n=$((n + 1))

  if [ -n "$MODEM" ]; then
    LOC=$(mmcli -m "$MODEM" --location-get 2>/dev/null || true)
    LAT=$(echo "$LOC" | sed -n 's/.*latitude: *\([-0-9.]*\).*/\1/p' | head -1)
    LON=$(echo "$LOC" | sed -n 's/.*longitude: *\([-0-9.]*\).*/\1/p' | head -1)
    ALT=$(echo "$LOC" | sed -n 's/.*altitude: *\([-0-9.]*\).*/\1/p' | head -1)
    if [ -n "$LAT" ] && [ -n "$LON" ]; then
      BODY="{\"lat\":$LAT,\"lon\":$LON"
      [ -n "$ALT" ] && BODY="$BODY,\"alt\":$ALT"
      BODY="$BODY}"
      curl -s -m 5 -X POST "$URL/ingest" -H "Authorization: Bearer $TOKEN" \
        -H "Content-Type: application/json" -d "$BODY" >/dev/null 2>&1 || true
    fi
  else
    MODEM=""
  fi
  sleep 2
done
SENDER
chmod 755 "$BIN"

cat > "$UNIT" <<'UNITFILE'
[Unit]
Description=Send GPS to irlmap.live
After=ModemManager.service network-online.target
Wants=network-online.target

[Service]
ExecStart=/usr/local/bin/irlmap-gps
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
UNITFILE

mmcli -m "$GPS_MODEM" --location-enable-gps-raw --location-enable-gps-nmea >/dev/null 2>&1 || true
mmcli -m "$GPS_MODEM" --location-set-gps-refresh-rate=1 >/dev/null 2>&1 || true
systemctl daemon-reload
systemctl enable --now irlmap-gps >/dev/null 2>&1 || systemctl restart irlmap-gps
say "  Service irlmap-gps installed and running."

# ---------------------------------------------------------------- first fix
step "Waiting for a GPS fix (up to 2 minutes, it helps to be outside)"
i=0
while [ $i -lt 24 ]; do
  LOC=$(mmcli -m "$GPS_MODEM" --location-get 2>/dev/null || true)
  LAT=$(echo "$LOC" | sed -n 's/.*latitude: *\([-0-9.]*\).*/\1/p' | head -1)
  if [ -n "$LAT" ]; then
    say "  Got a fix. Your position is being sent to irlmap.live."
    break
  fi
  i=$((i + 1))
  printf '.'
  sleep 5
done
if [ $i -ge 24 ]; then
  say ""
  say "  No fix yet. That's normal indoors. The service keeps trying in the background."
  say "  Satellites visible but never a position? See \"Sees satellites but never gets a position\""
  say "  on $URL/guides/belabox-gps-setup"
fi

say ""
say "Done. Locations only count while you're live on Twitch, so the service can run all the time."
say "Check it's arriving under Settings on $URL (the green connection check)."
say "Status:  systemctl status irlmap-gps      Remove:  curl -fsSL $URL/install/belabox.sh | sudo sh -s -- --uninstall"

Doing it by hand

Prefer to set it up yourself? These are the same steps the installer runs. First switch on GPS in ModemManager (replace 0 with your modem’s number from mmcli -L):

mmcli -m 0 --location-enable-gps-raw --location-enable-gps-nmea
mmcli -m 0 --location-set-gps-refresh-rate=1

Then save this as /usr/local/bin/irlmap-gps.sh with your own token in it:

#!/bin/sh
# Sends the modem's GPS position to irlmap.live every 2 seconds.
TOKEN="in_your_ingest_token"
MODEM="any"
n=0

while true; do
  # Modems sometimes get reset when a link drops, which turns GPS off again.
  # Re-enable it every minute so that never matters.
  if [ $((n % 30)) -eq 0 ]; then
    mmcli -m "$MODEM" --location-enable-gps-raw --location-enable-gps-nmea >/dev/null 2>&1
  fi
  n=$((n + 1))

  LOC=$(mmcli -m "$MODEM" --location-get 2>/dev/null)
  LAT=$(echo "$LOC" | sed -n 's/.*latitude: *\([-0-9.]*\).*/\1/p' | head -1)
  LON=$(echo "$LOC" | sed -n 's/.*longitude: *\([-0-9.]*\).*/\1/p' | head -1)
  ALT=$(echo "$LOC" | sed -n 's/.*altitude: *\([-0-9.]*\).*/\1/p' | head -1)

  if [ -n "$LAT" ] && [ -n "$LON" ]; then
    BODY="{\"lat\":$LAT,\"lon\":$LON"
    [ -n "$ALT" ] && BODY="$BODY,\"alt\":$ALT"
    BODY="$BODY}"
    curl -s -m 5 -X POST https://irlmap.live/ingest \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d "$BODY" >/dev/null
  fi
  sleep 2
done

And make it a service:

chmod +x /usr/local/bin/irlmap-gps.sh

cat > /etc/systemd/system/irlmap-gps.service <<'EOF'
[Unit]
Description=Send GPS to irlmap.live
After=ModemManager.service network-online.target
Wants=network-online.target

[Service]
ExecStart=/usr/local/bin/irlmap-gps.sh
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now irlmap-gps

Try it on your next stream

Free, and it takes about five minutes to set up.

Log in with Twitch See the live map