Skip to content

Guru-RF/Analog-HotSPOT-SVXLink

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

266 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SVXSpot: An SVXLink Analog Hotspot/Transceiver for the Raspberry Pi Zero

Quick Start

  1. Flash the image to an SD card (https://etcher.balena.io/#download-etcher): (The device already includes a freshly flashed SD card — you can skip this step and go straight to step 2.)

    https://storage.googleapis.com/rf-guru/rpi-images/hotspot-2025-12-09.img.gz

  2. Insert the SD card into the Raspberry Pi Zero 2W and power it with a stable 5V supply (usb port on the far right of the device).

  3. Wait for it to boot up. While waiting for boot you can subscribe to our RF Guru's Analog Hotspot mailinglist. https://listmonk.rf.guru/subscription/form

  4. Connect to the Wi-Fi AccessPoint of the Hotspot SSID:
    AccessPopup
    Password: 1234567890

  5. Open the dashboard:
    http://192.168.50.5/ (or http://hotspot.local)

  6. Open Shell → log in:

    • Username: hotspot
    • Password: hotspot

    screenshot

  7. Configure Wi-Fi (add as many networks you want, but do not remove AccessPopup):

     sudo nmtui
    

    (YouTube how-to) https://youtu.be/EJn0JkStWuY

    Note: When you save a new Wi-Fi network, the hotspot may immediately connect to it and disable the AccessPopup access point. Your PC will then lose the AccessPopup Wi-Fi connection (this is normal). Just connect your PC to your own Wi-Fi network, then reopen the portal via: http://hotspot.local (or use the announced IP address if mDNS is not available) login hotspot/hotspot and go to step 12.

  8. Reboot:

    sudo reboot
    
  9. After reboot, connect via:

  • http://hotspot.local
    or
  • the spoken IP address announced over RF (434.925 MHz — FM Narrow | 145.925 MHz — FM Narrow)
  • If this does not work, check whether the AccessPopup network is still being broadcast over Wi-Fi. If it is, something went wrong while entering your network details. Go back to point 6 and repeat the setup.
  1. Start configuration:

Use your own email adress ! And use real coordinates, some reflectors do not like hotspots info to be hidden ! Look at the local AUP! Callsigns in UPPERCASE !

sudo hotspot-config

(video demo https://youtu.be/bKF9JRo0ORM?t=125)

  1. For Belgian users, set the domain:

    be.svx.link is the domain, the portal of this domain is https://portal.be.svx.link

  2. After initial configuration, your SVXReflector sysop must sign your certificate.
    Once signed, your hotspot is fully operational.

  3. Continue setup:

We encourage everyone to leave Temperature tuning on !

Some people find the callsigns announcements in QSO's ennoying, you can turn this on or off here!

sudo hotspot-options
  1. Belgian users can update talkgroups + button presets:
sudo hotspot-on-webportal
  1. You are now ready to rumble 🎙️📡

4G/LTE Setup

Best to install these first — once 4G is up, wlan0 is brought down and you'll need an alternate way in if anything misbehaves:

For the 4G version install the module via: (it's default configured for the https://alwaysconnected.eu/ provider)

sudo install-4gmodule

Configure another provider

sudo hotspot-4g-config

Available Products


SVXLink Bookworm Image

Supports UHF and VHF on Raspberry Pi Zero 2W.

Default Configuration

UHF

  • 434.925 MHz — FM Narrow
  • CTCSS Input: 88.5 Hz
  • CTCSS Output: 250.3 Hz

VHF

  • 145.925 MHz — FM Narrow
  • CTCSS Input: 88.5 Hz
  • CTCSS Output: 250.3 Hz

Download

https://storage.googleapis.com/rf-guru/rpi-images/hotspot-2025-12-09.img.gz


Mailinglist for software updates

https://listmonk.rf.guru/subscription/form


Wi-Fi Setup (AccessPopup)

  1. Connect to:

    • SSID: AccessPopup
    • Password: 1234567890
  2. Open:
    http://192.168.50.5/

  3. Choose Shell.

Login

  • Username: hotspot
  • Password: hotspot

Configure Wi-Fi

    sudo nmtui

Reboot:

    sudo reboot

After reboot

If your router supports mDNS:

http://hotspot.local/

If not:
The hotspot announces its IP address over RF on the default frequency. (434.925 MHz — FM Narrow | 145.925 MHz — FM Narrow)

Tutorial video:
https://www.youtube.com/watch?v=bKF9JRo0ORM


Built-In Tools

  • D911# — Speaks IP address over RF
  • hotspot-frequency — Quick frequency setup
  • hotspot-options — Thermal + announcements
  • hotspot-talkgroups — Monitored TGs (and CTCSS-to-TG mapping on non-PRO chips); on PRO chips the first monitored TG becomes the default TG
  • hotspot-volume — Audio control

Supported PI's

  • Raspberry PI4
  • Raspberry PI5
  • Raspberry PiZero 2W
  • Raspberry Compute Module 4
  • Raspberry Compute Module 5

GPIO Pin Usage

  • Pin 3 → GPIO2
  • Pin 6 → GPIO3
  • Pin 35 → GPIO19
  • Pin 8 → TX
  • Pin 10 → RX
  • Pin 12 → CLK
  • Pin 32 → GPIO12 (COS input)
  • Pin 36 → GPIO16 (PTT)
  • Pin 38 → GPIO20
  • Pin 40 → GPIO21
  • Pin 31 → GPIO6
  • Pin 33 → GPIO13
  • Pin 25 → GPIO7
  • Pin 29 → GPIO5

iPhone Hotspot Notes

iOS does not broadcast the hotspot SSID continuously.
Open Settings → Personal Hotspot to force visibility.


Logs

sudo tail -f /var/log/svxlink

Monitoring and tuning the 4G link

Only relevant on 4G hotspots (the install-4gmodule flavour).

Watching connection attempts

The 4G stack logs to journald via two systemd units:

Service What it logs
hotspot-4g.service Connection attempts — "Attempt N/99", QMI device wait, registration wait, WDS session start, DHCP, "online" / "giving up after N attempts". Logs once per session/restart.
hotspot-4g-monitor.service Periodic health probes — "probe failed (N/3)", "link recovered after N failed probe(s)", "link stale — restarting hotspot-4g.service".
# Live, current session + new lines as they come
sudo journalctl -u hotspot-4g -f
sudo journalctl -u hotspot-4g-monitor -f

# Both at once
sudo journalctl -u hotspot-4g -u hotspot-4g-monitor -f

# Just this boot
sudo journalctl -u hotspot-4g -b --no-pager

# Last hour
sudo journalctl -u hotspot-4g --since "1 hour ago" --no-pager

The companion app's BLE feed (sg field) also shows the live signal strength — same data, no terminal.

Asking the modem directly

These work independently of our scripts — handy for sanity-checking:

# Is it registered? On which network / band?
sudo qmicli -p -d /dev/cdc-wdm0 --nas-get-serving-system

# Signal strength in dBm
sudo qmicli -p -d /dev/cdc-wdm0 --nas-get-signal-strength

# Which IP did the WDS session pull?
ip addr show wwan0
ip route | grep wwan0

Healthy output of the first command contains Registration state: 'registered' and your home network (or a roaming partner with Forbidden: 'no').

Stuck on a forbidden roaming partner

Symptom — --nas-get-serving-system shows:

Registration state: 'registration-denied'
Roaming status: 'on'
Forbidden: 'yes'

This is your roaming partner saying "your SIM provider isn't on my allowed-roamers list". The modem keeps camping on it because it has the strongest signal at your location, even though other carriers in range would accept the SIM. The fix is to bias the modem toward those other carriers.

1. See what's actually visible

sudo qmicli -p -d /dev/cdc-wdm0 --nas-network-scan

For each network you'll get an MCC, MNC, Description, and a Status flag list. Note the ones marked not-forbidden — those are your candidates.

2. Find the right MCC/MNC for your country

  • The scan output already shows it (MCC + MNC per network).
  • Or look it up on a reference like https://www.mcc-mnc.com/ — pick the carriers active in your area.

A few examples:

Country Carrier MCCMNC
Belgium Proximus 20601
Belgium BASE 20620
Belgium Orange BE 20610
Netherlands KPN 20408
Netherlands Vodafone NL 20404
Germany Telekom DE 26201
Germany Vodafone DE 26202
France Orange FR 20801
France SFR 20810

3. Pin the preferred-networks list

sudo qmicli -p -d /dev/cdc-wdm0 \
  --nas-set-preferred-networks="<MCCMNC>,<access_tech>,<MCCMNC>,<access_tech>,..."
sudo qmicli -p -d /dev/cdc-wdm0 --nas-force-network-search
sleep 8
sudo qmicli -p -d /dev/cdc-wdm0 --nas-get-serving-system   # expect 'registered'

<access_tech> varies by your libqmi version. Try in this order until one is accepted:

Try Notes
eutran Formal 3GPP name for LTE access. Most common on recent libqmi.
eutra Older libqmi spelling.
lte Newest libqmi spelling.
unspecified Matches any RAT — use as a fallback.

This setting is persistent in the modem's NV memory — it survives reboots and even hotspot-4g's low-power/online reset cycle. You don't have to redo it after every boot.

4. Make it survive an image re-flash too

For repeatability across SD-card re-flashes or modem factory resets, add it to /etc/hotspot-4g.conf:

PREFERRED_NETWORKS="20610,eutran,20601,eutran"

hotspot-4g re-applies this on every script start (only on the first attempt of the connect loop, so retries stay fast), so the bias is always in place after the SD card hits the device.

5. Kick the service to pick up the new registration

sudo systemctl restart hotspot-4g
sudo journalctl -u hotspot-4g -f

If the scan in step 1 showed only the forbidden carrier (rural area, no alternative coverage), preference-setting won't help — talk to your SIM provider about adding a roaming agreement with that carrier or switch to a SIM that has one.

To clear a preferred-networks list:

sudo qmicli -p -d /dev/cdc-wdm0 --nas-set-preferred-networks=""

Activating a Talkgroup

Preferred: DTMF

DTMF 91<TALKGROUP>#

This is the recommended over-the-air way to switch talkgroups. It doesn't disturb anyone else and it doesn't require being on TG0 first:

  • DTMF digits are muted at the hotspot (svxlink's DTMF_MUTING=1 in [Rx1]), so the network never hears your tones. You can't accidentally send a DTMF burst into someone's QSO.
  • No requirement to be on TG0 first. 91<TG># jumps straight from whichever talkgroup you're currently on.

You do still need a quiet moment to key your radio: the hotspot is half-duplex, so while it's transmitting (relaying audio from the network out over RF) you can't push DTMF into it. Wait for the hotspot to stop transmitting, then send the sequence — the switch happens locally and the next time you key up you're on the new TG.

Examples:

What DTMF
Switch to TG 91 9191#
Switch to TG 9000 919000#
Return to TG 0 (parking) 910#
Temporarily monitor another TG for one hour 94<TG># (e.g. 9423#)

Switching during active traffic — portal / Bluetooth app

If you want to switch while the hotspot is busy relaying a QSO (so you can't get DTMF in over the air), use one of the out-of-band channels — neither touches the radio:

  • Bluetooth companion app (preferred). Tap the talkgroup in the app and you're switched immediately, even mid-traffic. See the Installing Bluetooth section for the install and the Analog-HotSPOT-App.
  • Local web portal at http://hotspot.local (or the announced IP) — one click per talkgroup.

Alternative: CTCSS tone mapping (software-CTCSS chips only)

To activate a talkgroup, send the corresponding CTCSS tone from the CTCSS Talkgroup Mapping while in TG0.

You need to be in TG0, and you need to wait until there's no traffic — you'll hear a bleep tone 15 seconds after a QSO ended, that's your cue.

Once it switches it's instant – no double presses like before, you can start speaking immediately.

Caveats vs DTMF: you have to be on TG0 first, you have to remember the tone-to-TG mapping, and it's unavailable on SA818PRO hotspots (no software CTCSS decode — see CTCSS Talkgroup Mapping). DTMF works on every chip from any TG, so prefer DTMF over CTCSS.


Retrieving the Current IP Address

To get the current IP address of the hotspot, send:

DTMF D911#

Monitoring Multiple Talkgroups

To set up multiple talkgroups for monitoring, configure them in hotspot-config using this format:

8++, 23+, 50, 51, 52, 53, 54, 55

The TX CTCSS tone remains the same across all talkgroups. The plus signs (+) indicate priority levels. More plus signs mean higher priority. While a talk group is selected, and there is activity on a talk group with higher priority, the higher prio talk group will be selected.

Temporarily monitor (for one hour) another talkgroup:

DTMF 94#

Example for TG23:

9423#

CTCSS Talkgroup Mapping

Applies to every chip except the SA818PRO. The CTCSS-to-talkgroup mapping is a software-CTCSS feature implemented inside SVXLink — svxlink listens to the audio, decodes the tone, and switches talkgroups. Any radio module that hands raw audio to the Pi falls into this category: the original SA818, the SA818S-CE, the SA868, etc. — regardless of which board generation they're soldered onto. A 4th-gen board can ship with an SA818S-CE chip, in which case it uses this software-CTCSS mapping just like a 1st-gen board does.

Only the SA818PRO is different: it has hardware CTCSS decoding on-chip and drives a single squelch GPIO line, so svxlink doesn't decode anything itself and there's no per-tone mapping. On a PRO hotspot, talkgroup switching uses one of:

  • DTMF: 91<TG># to activate a talkgroup, 910# to return to TG0
  • Local portal (http://hotspot.local): one click per talkgroup
  • Bluetooth companion app (Analog-HotSPOT-App) — see the Installing Bluetooth section.

Many users on software-CTCSS boards also prefer DTMF / portal / BLE over the per-tone mapping because the mapping is easy to forget — the options above work everywhere.

You can map talkgroups via CTCSS tones using the following format:

tone:talkgroup, tone:talkgroup, …

Example default mapping:

67.0:8400, 69.3:8, 71.9:23, 74.4:9000, 77.0:50, 79.7:51, 82.5:52, 85.4:53, 88.5:54, 91.5:55

Mapping a single default talkgroup:

88.5:8

This maps CTCSS tone 88.5 to talkgroup 8.

To switch wait until hotspot is on talkgroup 0 or send DTMF 910#

Accessing the Local Portal

You can access the local dashboard:

  • Via hostname (if your network supports mDNS)
  • Or via the hotspot’s IP address

Choosing a Frequency and CTCSS Tone

We advise selecting a frequency not used by nearby repeaters. Do not use the ISM frequency 433.000 MHz.

Recommended defaults we use:

  • 70 cm: 439.100 MHz
  • 2 m: 145.250 MHz
  • CTCSS: 88.5 Hz

Use a tone/frequency not locally used.

For the CTCSS TX tone best to pick on between 67 and 85.4 (best audio quality)


Installing Bluetooth for the HotSpot companion app

Enables a BLE GATT service so a phone or laptop can drive the hotspot (send DTMF, restart SVXLink, toggle 4G, watch live state) without SSH.

Install on the hotspot:

    sudo /usr/sbin/install-bluetooth

If you get a “command not found” message, run hotspot-config again. Just press Enter and check that all settings are correct. It will download the latest software and update the hotspot, rerun install-bluetooth afterwards:

    sudo /usr/sbin/hotspot-config

After install, the device advertises over BLE as its hostname.

On the client (Windows / macOS / Linux / iOS / Android)

  • Turn Bluetooth on in the OS — that's all the OS-level setup needed.
  • Do not pair the hotspot in the system Bluetooth settings. You won't see it there anyway, and pairing isn't required.

This is Bluetooth Low Energy (BLE), not classic Bluetooth. BLE works differently from headphones / keyboards / car kits:

  • Devices expose GATT services identified by UUID. The companion app scans for the hotspot's service UUID directly and connects to it; the device never shows up in the OS "Bluetooth devices" list.
  • No pairing / PIN. The link is unencrypted and the hotspot accepts any client in radio range that knows the service UUID. (This is fine for a desk hotspot; if yours is mobile / public, see BLE.md for the bonded-mode flag.)
  • The OS radio just needs to be powered on so the app can use it.

Where to get the apps

All companion apps for every platform — macOS, Windows, Linux, Android, iPhone, iPad — are linked from the central download portal:

https://svxlink-hotspot.app

Analog-HotSPOT-App — standalone, works against any hotspot over BLE with no reflector-side dependency. Talkgroups are defined by the hotspot itself (MONITOR_TGS) and pushed to the app over the BLE feed.


Running multiple hotspots

Q: I have more than one hotspot — one at home, one in the car, a 4G one for the road. Can they all use my callsign?

Yes — but each hotspot needs its own unique callsign on the reflector. The reason isn't a simple name clash: SVXReflector authenticates every connection with a per-callsign certificate, and only one client can be logged in with that certificate at a time. Two hotspots configured with the same callsign would be trying to use the same certificate, and the reflector will refuse the second login (or kick the first one off, depending on how the sysop configured it).

The fix is a short suffix after a hyphen — up to 4 characters, your choice. Example layout for OR7F:

Hotspot Callsign
4G variant (mobile) OR7F-LTE
Home / Wi-Fi box OR7F-HOME
Car install OR7F-CAR

For each unique callsign you'll need to request a separate certificate signing from your reflector sysop — the cert is bound to the callsign, so a new callsign means a new cert. Plan the suffixes before you ask, so the sysop only has to sign once per box rather than chasing your edits.

Set the callsign via sudo hotspot-config on each hotspot, at the SVXLINK Reflector User Callsign prompt. The value lands in [ReflectorLogic] CALLSIGN= in /etc/svxlink/svxlink.conf.

What other operators see: on the reflector talker list each hotspot appears with its full callsign including the suffix (e.g. OR7F-LTE), so pick suffixes you're OK with being visible to everyone on the network.

The companion app doesn't need its own callsign. Analog-HotSPOT-App talks to a hotspot over BLE and just remote-controls it — connections to the reflector all come from the hotspot itself under its configured callsign. You can run the app on as many of your devices (phone, tablet, Mac, …) as you like simultaneously without any reflector-side collision.


Modify Talkgroups on the Dashboard

Edit base talkgroups:

    sudo vi /var/www/html/include/tgdb.php

Edit talkgroup buttons:

    sudo vi /var/www/html/include/config.inc.php

Backup the certificate

Note: the reflector certificate is only valid for 90 days and SVXLink renews it automatically as long as the hotspot is online and registered on the reflector. You normally don't need to back it up. This is mostly convenient when flashing a fresh SD card so you can skip the sysop-signing wait on the new install.

The reflector cert/key live under /var/lib/svxlink/pki/. Once your sysop has signed it, back it up so you don't have to wait for re-signing if you re-flash the SD card.

The hotspot already runs a local webserver at http://hotspot.local with its document root at /var/www/html/ — drop the tarball there and pull it from your laptop.

    sudo tar czf /var/www/html/svxlink-pki-$(hostname)-$(date +%Y%m%d).tgz -C /var/lib/svxlink pki

Download from the browser:

http://hotspot.local/svxlink-pki-<hostname>-<date>.tgz

Then immediately remove it from the web root — the private key is inside, and anyone on the same network can grab it while it sits there:

    sudo rm -f /var/www/html/svxlink-pki-*.tgz

To restore on a fresh install (after running hotspot-config once so the directory exists), copy the tarball back with scp using the default hotspot / hotspot login.

From your laptop:

    scp svxlink-pki-<hostname>-<date>.tgz hotspot@hotspot.local:/tmp/

On Windows: modern Windows 10/11 ships scp via OpenSSH so the command above works as-is in PowerShell. If you prefer a GUI, use WinSCP — connect to hotspot.local on port 22 with username hotspot / password hotspot, then drag the .tgz file into /tmp/ on the right-hand pane.

Then on the hotspot:

    sudo tar xzf /tmp/svxlink-pki-*.tgz -C /var/lib/svxlink
    sudo chown -R svxlink:svxlink /var/lib/svxlink/pki
    sudo rm -f /tmp/svxlink-pki-*.tgz
    sudo systemctl restart svxlink

Remove certificates (and request a new one)

    sudo rm -f /var/lib/svxlink/pki/*
    sudo systemctl restart svxlink

Raspberry Pi Connect

Connect remotely to your hotspot.

https://connect.raspberrypi.com

Install rpi-connect

    sudo apt -y install rpi-connect-lite
    loginctl enable-linger
    rpi-connect on
    rpi-connect signin

2nd USB port

The second USB port can be used for ethernet, or to attach an AMBE dongle for Bridging to DMR !


Repeater Mode

Extras useful when you're running the box as an actual repeater rather than a personal hotspot.

svxlink-watchdog

Watches GPIO16 (PTT) once per second. If the PTT line stays asserted (LOW) for more than 150 seconds, it assumes SVXLink is stuck in a keyed state and runs systemctl restart svxlink. While the pin is LOW, the script logs a countdown every 5 seconds.

Follow it live with:

sudo journalctl -t svxlink-watchdog -f

Install (no clone, no hotspot-config needed):

wget -qO- https://raw.githubusercontent.com/Guru-RF/Analog-HotSPOT-SVXLink/master/install-svxlink-watchdog.sh | sudo bash

The installer pulls the script + systemd unit, enables svxlink-watchdog.service, and starts it.


SVXLink Hotspot in Action

Svxlink.Hotspot.rPiZero.mp4

About

Complete source, Raspberry Pi image, and documentation for the RF.Guru analog hotspot. Includes SVXLink configs, scripts, GPIO handling, audio chain setup, and hardware integration for SA8X8-based VHF/UHF hotspots. Everything needed to build, flash, and run the hotspot.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors